PluginProbe ʕ •ᴥ•ʔ
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF / trunk
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF vtrunk
2.0.5 trunk 1.3.7 1.4.0 1.4.1 1.4.2 1.4.6 1.5.0 1.5.3 1.5.6 1.5.8 1.6.5 1.6.6 1.6.9 1.7.0 1.7.4 1.8.1 1.8.2 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4
robin-image-optimizer / libs / addons / includes / classes / class.folder.php
robin-image-optimizer / libs / addons / includes / classes Last commit date
format 3 months ago helpers 5 months ago models 5 months ago webp 3 months ago class.backup.php 5 months ago class.custom-folders.php 5 months ago class.folder-image.php 5 months ago class.folder.php 5 months ago class.folders-list-table.php 5 months ago class.gallery-nextgen.php 5 months ago class.image-nextgen.php 5 months ago class.image-statistic-folders.php 5 months ago class.image-statistic-nextgen.php 5 months ago class.wpcli-optimize.php 5 months ago index.php 5 months ago
class.folder.php
379 lines
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * Класс для работы с кастомными папками.
10 *
11 * @version 1.0
12 */
13 class WRIO_Folder {
14
15 /**
16 * @var string Folder path.
17 */
18 protected $path = '';
19
20 /**
21 * @var string SHA256 folder's path hash.
22 */
23 protected $uid = '';
24
25 /**
26 * @var int Number of files in current folder.
27 */
28 protected $files_count = 0;
29
30 /**
31 * @var int Number of optimized files in current folder.
32 */
33 protected $optimized_count = 0;
34
35 /**
36 * @var int Number of errors in current folder.
37 */
38 protected $errors_count = 0;
39
40 /**
41 * WRIO_Folder constructor.
42 *
43 * @param array $params List of params set on the model.
44 */
45 public function __construct( $params = [] ) {
46 // нужна проверка пути
47 foreach ( $params as $key => $value ) {
48 $this->set( $key, $value );
49 }
50 if ( ! $this->uid ) {
51 $this->uid = hash( 'sha256', $this->path );
52 }
53 }
54
55 /**
56 * Get specified object's property.
57 *
58 * @param string $property_name Property name.
59 *
60 * @return bool
61 */
62 public function get( $property_name ) {
63 if ( isset( $this->$property_name ) ) {
64 return $this->$property_name;
65 }
66
67 return false;
68 }
69
70 /**
71 * Set specified object's property.
72 *
73 * @param string $property_name Property name.
74 * @param mixed $value Value to set.
75 */
76 public function set( $property_name, $value ) {
77 if ( isset( $this->$property_name ) ) {
78 $this->$property_name = $value;
79 }
80 }
81
82 /**
83 * Convert object to associative array form.
84 *
85 * @return array
86 */
87 public function toArray() {
88 return [
89 'path' => $this->path,
90 'files_count' => $this->files_count,
91 'uid' => $this->uid,
92 'optimized_count' => $this->optimized_count,
93 'errors_count' => $this->errors_count,
94 ];
95 }
96
97 /**
98 * Об�
99 одит каталог и добавляет в индекс файлы
100 *
101 * @param mixed $offset отступ от начала
102 * @param mixed $max_process_elements кол-во элементов за итерацию
103 *
104 * @return int Кол-во элементов, обработанны�
105 при индексировании
106 */
107 public function indexing( $offset = 0, $max_process_elements = 100 ) {
108 global $wpdb;
109
110 $iterator = $this->getRecursiveIterator();
111 $allowed = $this->getAllowedFilesExt();
112 $files = [];
113 $db_table = RIO_Process_Queue::table_name();
114
115 foreach ( $iterator as $file ) {
116 $ext = substr( $file, strrpos( strtolower( $file ), '.' ) + 1 ); // получаем расширение файла
117 if ( in_array( strtolower( $ext ), $allowed ) ) {
118 // сделать путь относительно корня
119 $files[] = $this->real_path_to_relative( $file->getPathname() );
120 }
121 }
122
123 $files = array_slice( $files, $offset, $max_process_elements );
124 foreach ( $files as $file ) {
125 $file = wp_normalize_path( $file );
126 // $file_path = str_replace( $this->path, '', $file );
127 $file_uid = hash( 'sha256', str_replace( wp_normalize_path( ABSPATH ), '', $file ) );
128 $sql = $wpdb->prepare( "SELECT * FROM {$db_table} WHERE item_hash_alternative = %s AND item_hash = %s;", $this->uid, $file_uid );
129 $row = $wpdb->get_row( $sql );
130
131 if ( empty( $row ) ) {
132 // если файла нет в индексе - добавляем
133 $extra_data = new WRIO_CF_Image_Extra_Data(
134 [
135 'file_path' => $file,
136 'folder_relative_path' => $this->path,
137 ]
138 );
139 $optimization_data = new RIO_Process_Queue(
140 [
141 'item_type' => 'cf_image',
142 'item_hash' => $file_uid, // �
143 эш пути к файлу
144 'item_hash_alternative' => $this->uid, // �
145 эш директории будет сделан сеттером
146 'original_size' => 0,
147 'final_size' => 0,
148 'original_mime_type' => '',
149 'final_mime_type' => '',
150 'result_status' => 'unoptimized',
151 'processing_level' => '',
152 'extra_data' => $extra_data,
153 ]
154 );
155 $optimization_data->save();
156 } else {
157 // делаем апдейт и выставляем ласт индекс дату. Потом у кого в индексе ласт индекс дата меньше заданной, того уже нет на диске
158 }
159 }
160
161 return count( $files ); // сколько элементов обработано при индексировании.
162 }
163
164 /**
165 * Проверяет индекс на наличие несуществующи�
166 файлов.
167 *
168 * На�
169 одит файлы, которые пользователь удалил из папки, но в индексе они ещё есть.
170 * Удаляет из из индекса, вычитает из статистики
171 *
172 * @param mixed $offset отсутп от начала
173 * @param mixed $max_process_elements кол-во элементов за итерацию
174 *
175 * @return int $processed Кол-во обработанны�
176 записей. Используется для расчёта отступа
177 */
178 public function syncIndex( $offset = 0, $max_process_elements = 100 ) {
179 global $wpdb;
180 $db_table = RIO_Process_Queue::table_name();
181 $sql = $wpdb->prepare( "SELECT * FROM {$db_table} WHERE item_hash_alternative = %s LIMIT %d OFFSET %d;", $this->uid, $max_process_elements, $offset );
182 $rows = $wpdb->get_results( $sql );
183 $image_statistics = WRIO_Image_Statistic_Folders::get_instance();
184 $processed = 0;
185 $deleted = 0;
186
187 if ( ! empty( $rows ) ) {
188 foreach ( $rows as $row ) {
189 ++$processed;
190 $cf_image = new WRIO_Folder_Image( $row->id, $row );
191 if ( ! $cf_image->isFileExists() ) {
192 if ( $cf_image->isOptimized() ) {
193 // если файл оптимизирован - вычитаем из статистики
194 $optimization_data = $cf_image->getOptimizationData();
195 $optimized_size = $optimization_data->get_final_size();
196 $original_size = $optimization_data->get_original_size();
197 $webp_optimized_size = $optimization_data->get_extra_data()->get_webp_main_size();
198 $image_statistics->deductFromField( 'webp_optimized_size', $webp_optimized_size );
199 $image_statistics->deductFromField( 'optimized_size', $optimized_size );
200 $image_statistics->deductFromField( 'original_size', $original_size );
201 }
202 // если файла нет на диске - удаляем из индекса
203 $wpdb->delete(
204 $db_table,
205 [
206 'id' => $cf_image->get( 'id' ),
207 ],
208 [ '%d' ]
209 );
210 ++$deleted;
211 }
212 }
213 $image_statistics->save();
214 $this->reCountOptimizedFiles();
215 }
216 $processed = $processed - $deleted;
217
218 return $processed;
219 }
220
221 /**
222 * Get allowed list of extensions.
223 *
224 * @return array
225 */
226 public function getAllowedFilesExt() {
227 $allowed_formats = explode( ',', WRIO_Plugin::app()->getOption( 'allowed_formats', 'image/jpeg,image/png,image/gif' ) );
228 $allowed = [];
229 foreach ( $allowed_formats as $format ) {
230 if ( $format == 'image/jpeg' ) {
231 $allowed[] = 'jpg';
232 $allowed[] = 'jpeg';
233 } elseif ( $format == 'image/png' ) {
234 $allowed[] = 'png';
235 }
236 }
237
238 // $allowed = [ 'jpg', 'jpeg', 'png' ];
239
240 return $allowed;
241 }
242
243 /**
244 * Count number of files in a folder.
245 *
246 * @return int
247 */
248 public function countFiles() {
249 $iterator = $this->getRecursiveIterator();
250 $allowed = $this->getAllowedFilesExt();
251 $count = 0;
252 foreach ( $iterator as $file ) {
253 $ext = substr( $file, strrpos( strtolower( $file ), '.' ) + 1 ); // получаем расширение файла
254 if ( in_array( strtolower( $ext ), $allowed ) ) {
255 ++$count;
256 }
257 }
258
259 return $count;
260 }
261
262 /**
263 * Count number of indexes files.
264 *
265 * @return null|string
266 */
267 public function countIndexedFiles() {
268 global $wpdb;
269 $db_table = RIO_Process_Queue::table_name();
270 $sql_files = $wpdb->prepare( "SELECT COUNT(*) FROM {$db_table} WHERE item_type = %s AND item_hash_alternative = %s;", 'cf_image', $this->uid );
271 $files_count = $wpdb->get_var( $sql_files );
272
273 return $files_count;
274 }
275
276 public function reCountFiles() {
277 $this->files_count = $this->countFiles();
278
279 return $this->files_count;
280 }
281
282 /**
283 * Recount optimized files.
284 *
285 * @return int|null|string
286 */
287 public function reCountOptimizedFiles() {
288 global $wpdb;
289 $db_table = RIO_Process_Queue::table_name();
290 $sql = "SELECT COUNT(*) FROM {$db_table} WHERE item_type = %s AND result_status = %s AND item_hash_alternative = %s;";
291 $sql_prepared = $wpdb->prepare( $sql, 'cf_image', RIO_Process_Queue::STATUS_SUCCESS, $this->uid );
292 $optimized_count = $wpdb->get_var( $sql_prepared );
293 $this->optimized_count = $optimized_count;
294
295 return $this->optimized_count;
296 }
297
298 /**
299 * Remove folder and deduct its size from optimized and original size.
300 */
301 public function remove() {
302 // удаляем файлы из индекса и переситываем стату
303 global $wpdb;
304 $db_table = RIO_Process_Queue::table_name();
305 $sql = "SELECT SUM(original_size) AS original_size, SUM(final_size) AS optimized_size FROM {$db_table} WHERE item_type = %s AND result_status = %s AND item_hash_alternative = %s";
306 $prepared_sql = $wpdb->prepare( $sql, 'cf_image', RIO_Process_Queue::STATUS_SUCCESS, $this->uid );
307 $sum = $wpdb->get_row( $prepared_sql );
308
309 // Deduct from statistics
310 $image_statistics = WRIO_Image_Statistic_Folders::get_instance();
311 $webp_optimized_size = WRIO_Plugin::app()->updateOption( 'webp_optimized_size', 0 );
312 $image_statistics->deductFromField( 'webp_optimized_size', $webp_optimized_size );
313 $image_statistics->deductFromField( 'optimized_size', $sum->optimized_size );
314 $image_statistics->deductFromField( 'original_size', $sum->original_size );
315 $image_statistics->save();
316
317 // Delete from db
318 $wpdb->delete(
319 $db_table,
320 [
321 'item_hash_alternative' => $this->uid,
322 'item_type' => 'cf_image',
323 ],
324 [ '%s', '%s' ]
325 );
326 }
327
328 /**
329 * Get absolute path from relative.
330 *
331 * Same as 'wp_ajax_wriop_browse_dir'.
332 *
333 * @return bool|string
334 */
335 public function real_path() {
336 if ( is_main_site() ) {
337 $base_path = get_home_path();
338 } else {
339 $upload_dir = wp_upload_dir();
340 $base_path = $upload_dir['basedir'] . '/';
341 }
342 return realpath( $base_path . $this->path );
343 }
344
345 /**
346 * Returns the directory path relative to the site root
347 * Input: /home/user/test/wp.com/wp-content/uploads/custom-folder/
348 * Output: /wp-content/uploads/custom-folder/
349 *
350 * @param string $path Путь к директории. Может быть абсолютным.
351 *
352 * Same as 'wp_ajax_wriop_browse_dir'.
353 *
354 * @return string $relative_path относительный путь
355 */
356 public function real_path_to_relative( $path ) {
357 if ( is_main_site() ) {
358 $base_path = untrailingslashit( get_home_path() );
359 } else {
360 $upload_dir = wp_upload_dir();
361 $base_path = untrailingslashit( $upload_dir['basedir'] );
362 }
363 $relative_path = str_replace( $base_path, '', $path );
364
365 return $relative_path;
366 }
367
368 /**
369 * Get iterator to go scan files in directory.
370 *
371 * @return RecursiveIteratorIterator
372 */
373 public function getRecursiveIterator() {
374 $iterator = new RecursiveDirectoryIterator( $this->real_path() );
375
376 return new RecursiveIteratorIterator( $iterator );
377 }
378 }
379