source: spip-zone/_outils_/spip-cli/trunk/src/Command/ImagesVerifierExtensions.php @ 111669

Last change on this file since 111669 was 111669, checked in by marcimat@…, 3 months ago
  • Amélioration de l’affichage de la commande images:verifier:extensions
  • Update et mise à jour des composer.lock
  • Update de version, on passe ne 0.5.2
File size: 8.6 KB
Line 
1<?php
2
3namespace Spip\Cli\Command;
4
5use Spip\Cli\Console\Command;
6use Symfony\Component\Console\Input\InputInterface;
7use Symfony\Component\Console\Input\InputOption;
8use Symfony\Component\Console\Output\OutputInterface;
9
10
11class ImagesVerifierExtensions extends Command {
12
13        protected $requirements = [
14                'jpg' => 'JPEG image data',
15                'png' => 'PNG image data',
16                'gif' => 'GIF image data',
17        ];
18
19        protected $corrections_possibles_vers = [
20                'renommer' => ['png', 'jpg', 'gif'], // les logos n’ont que 3 extensions
21                'reecrire' => ['png', 'jpg', 'gif'], // les documents, on pourrait traiter plus de cas
22        ];
23
24        protected $dataDirectory;
25
26
27        protected function configure() {
28                $this->setName("images:verifier:extensions")
29                        ->setDescription("Vérifier les extensions d’images du répertoire IMG")
30                        ->addOption('logos', null, InputOption::VALUE_NONE, 'Uniquement les logos')
31                        ->addOption('documents', null, InputOption::VALUE_NONE, 'Uniquement les documents')
32                        ->addOption('extension', null, InputOption::VALUE_OPTIONAL, 'Uniquement cette extension. Choix : jpg, png, gif')
33                        ->addOption('reparer', null, InputOption::VALUE_NONE, 'Tente de réparer le format')
34                        ->addUsage("")
35                        ->addUsage("--logos --extension=jpg")
36                        ->addUsage("--documents")
37                        ->addUsage("--reparer")
38                        ->addUsage("--logos --reparer")
39                        ->addUsage("--documents --reparer")
40                ;
41        }
42
43        protected function execute(InputInterface $input, OutputInterface $output) {
44
45                $this->demarrerSpip();
46                $this->io->title("Analyse des extensions d’images du répertoire IMG");
47                $this->setDataDirectory(_DIR_IMG);
48
49                $extensions = array_keys($this->requirements);
50                if ($extension = $input->getOption('extension')) {
51                        if (!in_array($extension, $extensions)) {
52                                $this->io->error("Extension <info>$extension</info> inconnue. Possibles : " . implode(', ', $extensions));
53                                return;
54                        }
55                        $extensions = [$extension];
56                }
57
58                $logos = $input->getOption('logos');
59                $documents = $input->getOption('documents');
60                // tout par défaut.
61                if (!$logos and !$documents) {
62                        $logos = $documents = true;
63                }
64
65                $reparer = $input->getOption('reparer');
66
67                foreach ($extensions as $extension) {
68                        if ($logos) {
69                                $errors = $this->verifier_images_repertoire($extension, '', 'Logos');
70                                if ($errors and $reparer) {
71                                        $this->reparer_logos($errors);
72                                }
73                        }
74                        if ($documents) {
75                                $errors = $this->verifier_images_repertoire($extension, $extension . DIRECTORY_SEPARATOR, 'Documents');
76                                if ($errors and $reparer) {
77                                        $errors = $this->reparer_documents($errors);
78                                }
79                                if ($errors) {
80                                        $this->verifier_fichiers_en_base(array_keys($errors));
81                                }
82                        }
83                }
84        }
85
86        function setDataDirectory(string $dir) {
87                if (!is_dir($dir)) {
88                        throw new \Exception("Répertoire $dir inexistant.");
89                }
90                $this->dataDirectory = $dir;
91        }
92
93        function getDataDirectory() {
94                return $this->dataDirectory;
95        }
96
97        function log($log) {
98                spip_log($log, 'images.' . _LOG_INFO_IMPORTANTE);
99        }
100
101        function verifier_images_repertoire($extension, $repertoire, $titre) {
102                $this->io->section("$titre : $extension");
103                $base = $this->getDataDirectory();
104
105                $files = glob($base . $repertoire . '*.' . $extension);
106
107                $this->io->text(count($files) . " Fichiers");
108                if (!count($files)) {
109                        return;
110                }
111
112                $this->io->progressStart(count($files));
113                $errors = [];
114                foreach ($files as $file) {
115                        list($ok, $desc) = $this->verifier_fichier($file, $extension);
116                        if (!$ok) {
117                                $name = str_replace($base, '', $file);
118                                $errors[ $file ] = "<comment>$name</comment> : $desc";
119                        }
120                        $this->io->progressAdvance();
121                }
122                $this->io->progressFinish();
123                if ($errors) {
124                        $this->io->fail(count($errors) . ' fichiers erronnés');
125                        $this->io->listing($errors);
126                } else {
127                        $this->io->check('Tous les fichiers sont corrects');
128                }
129                return $errors;
130        }
131
132        function verifier_fichier($file, $extension) {
133                $infos = `file {$file}`;
134                $ok = (false !== strpos($infos, $this->requirements[$extension]));
135                list (, $desc) = explode(':', $infos, 2);
136                return [$ok, trim($desc)];
137        }
138
139        function reparer_logos(array $errors) {
140                return $this->reparer($errors, 'renommer');
141        }
142
143        function reparer_documents(array $errors) {
144                return $this->reparer($errors, 'reecrire');
145        }
146
147
148        protected function reparer(array $errors, $mode = 'renommer') {
149                $this->io->section("Réparer " . count($errors) . " fichiers");
150                if (!in_array($mode, ['renommer', 'reecrire'])) {
151                        $this->io->error("Mode $mode inconnu");
152                        return false;
153                }
154
155                $echecs = [];
156                $this->io->progressStart(count($errors));
157                foreach ($errors as $file => $info) {
158                        $extension = $this->getExtensionFromInfo($info);
159                        if (!$extension) {
160                                $echecs[$file] = $info;
161                        } else {
162                                if ($mode == 'renommer') {
163                                        $err = $this->reparer_renommer($file, $extension);
164                                } else {
165                                        $err = $this->reparer_reecrire($file, $extension);
166                                }
167                                if ($err) {
168                                        $echecs[$file] = $info . "\n<error>$err</error>";
169                                }
170                        }
171                        $this->io->progressAdvance();
172                }
173                $this->io->progressFinish();
174                if ($echecs) {
175                        $this->io->fail(count($echecs) . " fichiers non réparés");
176                        $this->io->listing($echecs);
177                } else {
178                        $this->io->check("Tous les fichiers sont réparés");
179                }
180                return $echecs;
181        }
182
183        protected function reparer_renommer($file, $extension) {
184                if (!in_array($extension, $this->corrections_possibles_vers['renommer'])) {
185                        return "Renommage vers $extension non traitable";
186                }
187                $p = pathinfo($file);
188                $fromName = $p['basename'];
189                $toName = $p['filename'] . "." . $extension;
190                if (!rename($file,  $p['dirname'] . DIRECTORY_SEPARATOR. $toName)) {
191                        return "Echec du renommage ($fromName en  $toName)";
192                }
193                $this->log("Image $fromName corrigée (renommage) en $toName");
194                return '';
195        }
196
197        protected function reparer_reecrire($file, $extensionFrom) {
198                $extension = pathinfo($file, PATHINFO_EXTENSION);
199                if (!in_array($extension, $this->corrections_possibles_vers['reecrire'])) {
200                        return "Réécriture vers $extension non traitable";
201                }
202                $name = basename($file);
203                $function = $this->getGdReadFunctionFromExtension($extensionFrom);
204                if (!function_exists($function) or !$image = $function($file)) {
205                        if (!$image = imagecreatefromstring(file_get_contents($file))) {
206                                return "Echec lecture de l’image ($name)";
207                        }
208                }
209                $err = $this->creer_image($image, $extension, $file);
210                imagedestroy($image);
211                if ($err) {
212                        return $err;
213                }
214                $this->log("Image $name corrigée (reecrite) en $extension");
215                return '';
216        }
217
218
219        protected function getExtensionFromInfo($info) {
220                foreach ($this->requirements as $extension => $req) {
221                        if (false !== strpos($info, $req)) {
222                                return $extension;
223                        }
224                }
225                return false;
226        }
227
228        protected function getGdReadFunctionFromExtension($extension) {
229                $term = ($extension == 'jpg') ? 'jpeg' : $extension;
230                return "imagecreatefrom$term";
231        }
232
233        protected function getGdWriteFunctionFromExtension($extension) {
234                $term = ($extension == 'jpg') ? 'jpeg' : $extension;
235                return "image$term";
236        }
237
238        protected function creer_image($image, $extension, $fichier) {
239                $function = $this->getGdWriteFunctionFromExtension($extension);
240                if (!function_exists($function)) {
241                        return "Function $function indisponible";
242                }
243
244                $tmp = $fichier . ".tmp";
245                $ret = $function($image, $tmp);
246                if (!$ret) {
247                        if (file_exists($tmp)) {
248                                unlink($tmp);
249                        }
250                        return "Échec création image temporaire : " . basename($tmp);
251                }
252
253                if (!file_exists($tmp)) {
254                        return "Image temporaire absente après création : " . basename($tmp);
255                }
256
257                $taille_test = getimagesize($tmp);
258                if ($taille_test[0] < 1) {
259                        return "Image temporaire taille nulle : " . basename($tmp);
260                }
261
262                list($ok, $desc) = $this->verifier_fichier($tmp, $extension);
263                if (!$ok) {
264                        return "Image temporaire pas du type attendu : " . basename($tmp) . " ($desc)";
265                }
266
267                if (file_exists($fichier)) {
268                        unlink($fichier);
269                }
270
271                if (!rename($tmp, $fichier)) {
272                        return "Échec renommage de " . basename($tmp) . " en " . basename($fichier);
273                }
274
275                return "";
276        }
277
278        protected function verifier_fichiers_en_base($files) {
279                $base = $this->getDataDirectory();
280                $_files = array_map(function($file) use ($base) {
281                        return substr($file, strlen($base));
282                }, $files);
283
284                $presents = sql_allfetsel('id_document, fichier', 'spip_documents', sql_in('fichier', $_files));
285                if ($presents) {
286                        $presents = array_column($presents, 'fichier');
287                        $_files = array_diff($_files, $presents);
288                }
289
290                if ($_files) {
291                        $this->io->text("<info>Fichiers absents dans spip_documents :</info>");
292                        $this->io->text("Ils peuvent peut être être supprimés du coup…");
293                        $this->io->listing(array_map(function($file) { return "<comment>$file</comment>"; }, $_files));
294                } else {
295                        $this->io->text("Tous les fichiers en erreur sont présents dans spip_documents.");
296                }
297                return $files;
298        }
299}
Note: See TracBrowser for help on using the repository browser.