source: spip-zone/_plugins_/medias_dereferencer/branches/v1/medias_dereferencer_fonctions.php @ 98423

Last change on this file since 98423 was 98423, checked in by teddy.spip@…, 3 years ago

Importation du bugfix dans la branche

File size: 18.5 KB
Line 
1<?php
2
3/**
4 * Fonctions utiles au plugin Déréférencer les médias.
5 *
6 * @plugin     Déréférencer les médias
7 *
8 * @copyright  2015-2016
9 * @author     Teddy Payet
10 * @licence    GNU/GPL
11 */
12if (!defined('_ECRIRE_INC_VERSION')) {
13        return;
14}
15
16/**
17 * Lister les champs de type text (TINYTEXT, TEXT, MEDIUMTEXT, et LONGTEXT) des différentes tables principales de SPIP.
18 *
19 * @return array
20 *               Tableau avec pour clé le nom de la table.
21 */
22function medias_lister_champs_texte() {
23        include_spip('base/objets');
24        $lister_tables_objets_sql = lister_tables_objets_sql();
25        $lister_tables_principales = lister_tables_principales();
26        $lister_tables_principales = array_keys($lister_tables_principales); /* Pas de fonction en paramètre d'une fonction, cela évite des warnings. */
27        $champs_texte = array();
28        foreach ($lister_tables_objets_sql as $table => $valeur) {
29                /**
30                 * On ne prend que les objets qui font partis des tables principales de SPIP.
31                 * Donc, on ne prend pas les tables telles que spip_visites, spip_referers, etc.
32                 * C'est une sécurité.
33                 */
34                $id_primary_double = preg_match('/,/', $valeur['key']['PRIMARY KEY']); /* l'id_primary doit faire référence à un seul champ */
35                if (in_array($table, $lister_tables_principales) and $id_primary_double == 0) {
36                        $champs_texte[$table] = array(); /* Instanciation de la variable */
37                        $champs_texte[$table]['id_primary'] = $valeur['key']['PRIMARY KEY'];
38                        $champs_texte[$table]['objet'] = objet_type($champs_texte[$table]['id_primary']);
39                        $champs_texte[$table]['statut'] = (isset($valeur['field']['statut']) ? true : false);
40                        $champs_texte[$table]['publie'] = (isset($champs_texte[$table]['statut']) and isset($valeur['statut'][0]['publie']) ? $valeur['statut'][0]['publie'] : false);
41
42                        foreach ($valeur['field'] as $champs => $descriptif) {
43                                if (preg_match('/text/', $descriptif)) {
44                                        $champs_texte[$table]['texte'][] = $champs;
45                                }
46                        }
47                        if (isset($champs_texte[$table]['texte'])) {
48                                $champs_texte[$table]['texte'] = implode(',', $champs_texte[$table]['texte']);
49                        } else {
50                                unset($champs_texte[$table]);
51                        }
52                }
53        }
54        $champs_texte = array_filter($champs_texte);
55
56        return $champs_texte;
57}
58
59/**
60 * On regarde les raccourcis typo <docXXX> <embXXX> <imgXXX> utilisés
61 * dans les champs de type texte d'un objet éditorial.
62 * Si cet objet a un statut, on prend ce statut comme référence pour le document.
63 *
64 * @return array
65 */
66function medias_lister_medias_used_in_text() {
67        include_spip('base/abstract_sql');
68
69        $tables_texte = medias_lister_champs_texte();
70        $documents = array();
71        $statut = 'publie';
72        foreach ($tables_texte as $table => $champs) {
73                $statut_requete = '';
74                if (isset($champs['statut']) and $champs['statut'] and $champs['objet'] != 'auteur') {
75                        $statut_requete = ', statut';
76                }
77                $resultats = sql_allfetsel($champs['id_primary'] . ' as id_primary, CONCAT(' . $champs['texte'] . ') as texte_tmp' . $statut_requete, $table);
78                foreach ($resultats as $resultat => $value) {
79                        // On recherche les raccourcis typographiques
80                        if (preg_match_all('/(doc|img|emb|video)([0-9]+)/', $value['texte_tmp'], $docs)) {
81                                // On a au moins un résultat, alors on commence le traitement.
82                                if (isset($value['statut']) and $value['statut'] == $champs['publie']) {
83                                        /**
84                                         * l'objet a un statut et est publié ou actif,
85                                         * alors le document doit-être publié aussi.
86                                         */
87                                        $statut = 'publie';
88                                } elseif (isset($value['statut']) and $value['statut'] != $champs['publie']) {
89                                        // l'objet a un statut et n'est publié ou actif,
90                                        // alors le document doit-être en préparation.
91                                        $statut = 'prepa';
92                                } elseif (!isset($value['statut'])) {
93                                        /**
94                                         * L'objet n'a pas de statut
95                                         * et donc son affichage n'est pas conditionné par le statut,
96                                         * alors le document sera publié.
97                                         */
98                                        $statut = 'publie';
99                                }
100                                // On stocke maintenant toutes ces infos pour chaque document trouvé.
101                                foreach ($docs[2] as $id_doc) {
102                                        /** structure du tableau :
103                                         * 0 : id_document
104                                         * 1 : id_objet
105                                         * 2 : objet
106                                         * 3 : vu (oui ou non)
107                                         * 4 : statut du document
108                                         */
109                                        $documents[] = array(
110                                                'id_document' => $id_doc,
111                                                'id_objet' => $value['id_primary'],
112                                                'objet' => $champs['objet'],
113                                                'vu' => 'oui',
114                                                'statut' => $statut,
115                                        );
116                                }
117                        }
118                }
119        }
120        // asort($documents);
121        // $documents = array_values(array_unique($documents));
122
123        return $documents;
124}
125
126/**
127 * Mettre à jour le statut des documents publiés liés à des objets non publiés.
128 * Ces documents doivent donc avoir un statut 'prepa' et non 'publie'.
129 *
130 * @return bool
131 */
132function medias_maj_documents_lies() {
133        include_spip('base/abstract_sql');
134        include_spip('base/objets');
135        include_spip('inc/session');
136        $message_log = array();
137        $message_log[] = "\n-----";
138        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
139        $message_log[] = 'Fonction : ' . __FUNCTION__;
140        if (session_get('id_auteur')) {
141                // S'il y a un auteur authentifié, on indique que c'est lui qui a lancé l'action.
142                $message_log[] = "L'action a été lancé par l'auteur #" . session_get('id_auteur') . ', ' . session_get('nom') . ' (' . session_get('statut') . ')';
143        } else {
144                // S'il n'y a pas d'auteur authentifié, c'est SPIP qui lance le script en tâche de fond.
145                $message_log[] = "L'action a été lancé par SPIP en tâche de fond.";
146        }
147
148        // On ne s'occupe que des objets pour lesquels on a des liens avec des documents.
149        $objets_lies = sql_fetsel('DISTINCT objet', 'spip_documents_liens');
150        foreach ($objets_lies as $objet_lie) {
151                /**
152                 * exemple de requête demandée :
153                 * SELECT * FROM spip_documents
154                 * WHERE id_document IN (SELECT DISTINCT id_document FROM spip_documents_liens WHERE objet='article' AND id_objet IN (SELECT id_article FROM spip_articles WHERE statut NOT IN ('publie')))
155                 * AND statut IN ('publie')
156                 *****
157                 * Sélectionner tous les documents publiés liés à des objets non publiés
158                 *****
159                 */
160                $documents = sql_allfetsel('id_document,statut', 'spip_documents', "statut IN ('publie') AND id_document IN (SELECT DISTINCT id_document FROM spip_documents_liens WHERE objet='" . $objet_lie . "' AND id_objet IN (SELECT " . id_table_objet($objet_lie) . ' FROM ' . table_objet_sql($objet_lie) . " WHERE statut NOT IN ('publie')))");
161                if (is_array($documents) and count($documents) > 0) {
162                        foreach ($documents as $document) {
163                                if (sql_updateq('spip_documents', array('statut' => 'prepa'), 'id_document=' . $document['id_document'])) {
164                                        $message_log[] = 'Le statut du document #' . $document['id_document'] . ' lié à l\'objet ' . $objet_lie . ' a bien été mis à jour avec le statut \'' . $document['statut'] . '\'';
165                                }
166                        }
167                }
168        }
169        // Par défaut, le message de log a 4 entrées. Voir en début de la présente fonction.
170        if (count($message_log) == 4) {
171                $message_log[] = 'Il n\'y a pas eu d\'action à faire en base de données.';
172        }
173        // On met l'heure de fin de la procédure dans le message de log
174        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
175        $message_log[] = "-----\n";
176        // Et maintenant on stocke les messages dans un fichier de log.
177        include_spip('inc/utils');
178        spip_log(implode("\n", $message_log), 'medias_dereferencer');
179
180        return true;
181}
182
183/**
184 * Cette fonction récupère les medias qui ont été utilisé par raccourcis typographiques dans les champs de type text. Et crée les liens entre le media et l'objet. Puis met à jour le statut du media.
185 *
186 * @uses   medias_lister_medias_used_in_text()
187 *
188 * @return [type] [description]
189 */
190function medias_maj_documents_non_lies() {
191        include_spip('base/abstract_sql');
192        include_spip('base/objets');
193        include_spip('inc/session');
194        $documents_raccourcis = medias_lister_medias_used_in_text();
195        $liste_documents = array();
196        $message_log = array();
197        $message_log[] = "\n-----";
198        // On met l'heure de début de la procédure dans le message de log
199        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
200        $message_log[] = 'Fonction : ' . __FUNCTION__;
201        if (session_get('id_auteur')) {
202                // S'il y a un auteur authentifié, on indique que c'est lui qui a lancé l'action.
203                $message_log[] = "L'action a été lancé par l'auteur #" . session_get('id_auteur') . ', ' . session_get('nom') . ' (' . session_get('statut') . ')';
204        } else {
205                // S'il n'y a pas d'auteur authentifié, c'est SPIP qui lance le script en tâche de fond.
206                $message_log[] = "L'action a été lancé par SPIP en tâche de fond.";
207        }
208
209        // On lance les opérations uniquement si on a des documents utilisés en raccourcis.
210        if (is_array($documents_raccourcis) and count($documents_raccourcis) > 0) {
211                foreach ($documents_raccourcis as $document) {
212                        if (sql_countsel('spip_documents_liens', array(
213                                'id_document=' . sql_quote($document['id_document']),
214                                'id_objet=' . sql_quote($document['id_objet']),
215                                'objet=' . sql_quote($document['objet']),
216                                'vu NOT IN (' . sql_quote($document['vu']) . ')',
217                        ))) {
218                                // Le lien de ce media avec l'objet existe mais n'a pas la bonne valeur dans 'vu'
219                                // Donc on met à jour la valeur de 'vu' pour ce lien.
220                                if (sql_updateq('spip_documents_liens', array(
221                                        'vu' => $document['vu'],
222                                ), 'id_document=' . sql_quote($document['id_document']) . ' AND id_objet=' . sql_quote($document['id_objet']) . ' AND objet=' . sql_quote($document['objet']) . ' AND vu NOT IN (' . sql_quote($document['vu']) . ')')) {
223                                        $message_log[] = 'Le lien entre le document #' . $document['id_document'] . ' et l\'objet ' . $document['objet'] . ' #' . $document['id_objet'] . ' a bien été mis à jour avec la vu \'' . $document['vu'] . '\'';
224                                }
225                                // et on met à jour le statut dudit document si le statut est différent uniquement.
226                                if (sql_updateq('spip_documents', array('statut' => $document['statut']), 'id_document=' . sql_quote($document['id_document']) . ' AND statut NOT IN (' . sql_quote($document['statut']) . ')')) {
227                                        $message_log[] = 'Le statut du document #' . $document['id_document'] . ' lié à l\'objet ' . $document['objet'] . ' #' . $document['id_objet'] . ' a bien été mis à jour avec le statut \'' . $document['statut'] . '\'';
228                                }
229                        } elseif (!sql_countsel('spip_documents_liens', array(
230                                'id_document=' . sql_quote($document['id_document']),
231                                'id_objet=' . sql_quote($document['id_objet']),
232                                'objet=' . sql_quote($document['objet']),
233                                'vu IN (' . sql_quote($document['vu']) . ')',
234                        ))
235                        ) {
236                                // Le lien de ce média avec l'objet n'existe pas
237                                // Alors on l'insère dans la table
238                                if (sql_insertq('spip_documents_liens', array(
239                                                'id_document' => $document['id_document'],
240                                                'id_objet' => $document['id_objet'],
241                                                'objet' => $document['objet'],
242                                                'vu' => $document['vu'],
243                                        )) and lire_config('medias_dereferencer/lier_document') === 'oui'
244                                ) {
245                                        $message_log[] = 'Le lien entre le document #' . $document['id_document'] . ' et l\'objet ' . $document['objet'] . ' #' . $document['id_objet'] . ' a bien été inséré en base de données avec la vu \'' . $document['vu'] . '\'';
246                                }
247                                // et on met à jour le statut dudit document si le statut est différent uniquement.
248                                if (sql_updateq('spip_documents', array('statut' => $document['statut']), 'id_document=' . sql_quote($document['id_document']) . ' AND statut NOT IN (' . sql_quote($document['statut']) . ')')) {
249                                        $message_log[] = 'Le statut du document #' . $document['id_document'] . ' lié à l\'objet ' . $document['objet'] . ' #' . $document['id_objet'] . ' a bien été mis à jour avec le statut \'' . $document['statut'] . '\'';
250                                }
251                        }
252                        /**
253                         * On stocke par statut les documents pour faire une mise à jour par lot
254                         */
255                        $liste_documents[$document['statut']][] = $document['id_document'];
256                }
257                if (is_array($liste_documents) and count($liste_documents) > 1) {
258                        // Si un document est déjà dans 'publie', il ne doit pas être présent dans le tableau 'prepa'
259                        $liste_documents['prepa'] = array_diff($liste_documents['prepa'], $liste_documents['publie']);
260                        // On met à jour les documents en cours de préparation
261                        sql_updateq('spip_documents', array('statut' => 'prepa'), 'id_document IN (' . implode(',', $liste_documents['prepa']) . ')');
262                        // On met à jour les documents publiés
263                        sql_updateq('spip_documents', array('statut' => 'publie'), 'id_document IN (' . implode(',', $liste_documents['publie']) . ')');
264                }
265        }
266        // Par défaut, le message de log a 4 entrées. Voir en début de la présente fonction.
267        if (count($message_log) == 4) {
268                $message_log[] = 'Il n\'y a pas eu d\'action à faire en base de données.';
269        }
270        // on met l'heure de fin de la procédure dans le message de log
271        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
272        $message_log[] = "-----\n";
273        // Et maintenant on stocke les messages dans un fichier de log.
274        include_spip('inc/utils');
275        spip_log(implode("\n", $message_log), 'medias_dereferencer');
276
277        return true;
278}
279
280/**
281 * Cette fonction va créer pour chaque répertoire d'extension de documents non publiés un fichier .htaccess
282 * Toutefois, il faut que le répertoire IMG/ext existe et soit accessible en écriture.
283 *
284 * @return bool
285 */
286function md_creation_htaccess_img() {
287        include_spip('base/abstract_sql');
288        include_spip('inc/config');
289        include_spip('inc/session');
290        $config_md = lire_config('medias_dereferencer');
291        $message_log = array();
292        $message_log[] = "\n-----";
293        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
294        $message_log[] = 'Fonction : ' . __FUNCTION__;
295        if (session_get('id_auteur')) {
296                // S'il y a un auteur authentifié, on indique que c'est lui qui a lancé l'action.
297                $message_log[] = "L'action a été lancé par l'auteur #" . session_get('id_auteur') . ', ' . session_get('nom') . ' (' . session_get('statut') . ')';
298        } else {
299                // S'il n'y a pas d'auteur authentifié, c'est SPIP qui lance le script en tâche de fond.
300                $message_log[] = "L'action a été lancé par SPIP en tâche de fond.";
301        }
302
303        /*
304         * On sélectionne les extensions des documents avec un statut en prepa,
305         * pour ne pas être trop gourmand en écriture sur le serveur.
306         */
307        $extensions_documents = sql_allfetsel('DISTINCT(extension)', 'spip_documents', "statut='prepa'");
308        if (is_array($extensions_documents) and count($extensions_documents) > 0) {
309                foreach ($extensions_documents as $extension) {
310                        if (is_readable(_DIR_IMG . $extension['extension']) and $config_md['htaccess'] === 'oui') {
311                                $medias_htaccess = recuperer_fond('inclure/medias_htaccess', $extension);
312                                if (function_exists('fopen') and $ht = fopen(_DIR_IMG . $extension['extension'] . '/' . _ACCESS_FILE_NAME, 'w')) {
313                                        fputs($ht, $medias_htaccess);
314                                        fclose($ht);
315                                        @chmod(_DIR_IMG . $extension['extension'] . '/' . _ACCESS_FILE_NAME, _SPIP_CHMOD & 0666);
316                                        $message_log[] = 'Le fichier ' . _ACCESS_FILE_NAME . ' pour ' . _DIR_IMG . $extension['extension'] . ' a été créé. ' . date_format(date_create(), 'Y-m-d H:i:s');
317                                } else {
318                                        $message_log[] = 'Le fichier ' . _ACCESS_FILE_NAME . ' pour ' . _DIR_IMG . $extension['extension'] . " n'a pu être créé. " . date_format(date_create(), 'Y-m-d H:i:s');
319                                }
320                        }
321                }
322        }
323
324        /*
325         * Par défaut, le message de log a 4 entrées. Voir en début de la présente fonction.
326         */
327        if (count($message_log) == 4) {
328                $message_log[] = 'Aucun fichier ' . _ACCESS_FILE_NAME . " n'a été créé. " . date_format(date_create(), 'Y-m-d H:i:s');
329        }
330        // on met l'heure de fin de la procédure dans le message de log
331        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
332        $message_log[] = "-----\n";
333        // Et maintenant on stocke les messages dans un fichier de log.
334        include_spip('inc/utils');
335        spip_log(implode("\n", $message_log), 'medias_dereferencer');
336
337        if (count($message_log) > 7) {
338                return true;
339        }
340
341        return false;
342}
343
344/**
345 * Cette fonction supprime tous les fichiers htaccess qui se trouveraient dans les différents répertoires d'extensions dans IMG/
346 *
347 * @return bool
348 */
349function md_suppression_htaccess_img() {
350        include_spip('inc/flock');
351        include_spip('inc/session');
352        include_spip('inc/utils');
353        $message_log = array();
354        $message_log[] = "\n-----";
355        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
356        $message_log[] = 'Fonction : ' . __FUNCTION__;
357        if (session_get('id_auteur')) {
358                // S'il y a un auteur authentifié, on indique que c'est lui qui a lancé l'action.
359                $message_log[] = "L'action a été lancé par l'auteur #" . session_get('id_auteur') . ', ' . session_get('nom') . ' (' . session_get('statut') . ')';
360        } else {
361                // S'il n'y a pas d'auteur authentifié, c'est SPIP qui lance le script en tâche de fond.
362                $message_log[] = "L'action a été lancé par SPIP en tâche de fond.";
363        }
364
365        /*
366         * On recherche les extensions des documents sans distinction de statut des documents.
367         */
368        $extensions_documents = sql_allfetsel('DISTINCT(extension)', 'spip_documents');
369        if (is_array($extensions_documents) and count($extensions_documents) > 0) {
370                foreach ($extensions_documents as $extension) {
371                        if (is_readable(_DIR_IMG . $extension['extension'])) {
372                                spip_unlink(_DIR_IMG . $extension['extension'] . '/' . _ACCESS_FILE_NAME);
373                                $message_log[] = 'Le fichier ' . _ACCESS_FILE_NAME . ' pour ' . _DIR_IMG . $extension['extension'] . ' a été supprimé avec succès.';
374                        }
375                }
376        }
377
378        // Par défaut, le message de log a 4 entrées. Voir en début de la présente fonction.
379        if (count($message_log) == 4) {
380                $message_log[] = 'Aucun fichier ' . _ACCESS_FILE_NAME . " n'a été supprimé. " . date_format(date_create(), 'Y-m-d H:i:s');
381        }
382        // on met l'heure de fin de la procédure dans le message de log
383        $message_log[] = date_format(date_create(), 'Y-m-d H:i:s');
384        $message_log[] = "-----\n";
385        // Et maintenant on stocke les messages dans un fichier de log.
386        spip_log(implode("\n", $message_log), 'medias_dereferencer');
387
388        if (count($message_log) > 7) {
389                return true;
390        }
391
392        return false;
393}
394
395/**
396 * Lister les adresses IP au format Apache/htaccess qui ont été renseignées dans le formulaire de configuration.
397 *
398 * @return bool|string
399 *         false : il n'y a pas d'adresses IP renseignées dans le formulaire de configuration
400 *         string : liste des adresses IP autorisées formatées selon la version d'Apache.
401 */
402function md_adresses_allow() {
403        include_spip('inc/config');
404        $config_md = lire_config('medias_dereferencer');
405        $directive = 'Allow from'; /* Apache <2.4 */
406        if (isset($config_md['adresse_ip']) and empty($config_md['adresse_ip'])) {
407                return false;
408        }
409        if (!is_array($config_md['adresse_ip'])) {
410                $config_md['adresse_ip'] = explode(';', $config_md['adresse_ip']);
411        }
412        if (isset($config_md['apache']) and $config_md['apache'] === 'oui') {
413                $directive = 'Require not ip'; /* Apache 2.4 minimum */
414        }
415        $config_md['adresse_ip'] = array_filter($config_md['adresse_ip']);
416        $string = "    $directive " . implode("\n    $directive ", $config_md['adresse_ip']);
417
418        return $string;
419}
Note: See TracBrowser for help on using the repository browser.