PluginProbe
Document Gallery / 2.0.1
Document Gallery v2.0.1
trunk 0.8 0.8.5 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1 1.2 1.2.1 1.3 1.3.1 1.4 1.4.1 1.4.2 1.4.3 2.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 94 releases
document-gallery / inc / class-thumber.php

class-thumber.php in Document Gallery 2.0.1, at inc/class-thumber.php

788 lines 26.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('WPINC') OR exit;
3
4 /**
5 * Thumber wraps the functionality required to
6 * generate thumbnails for arbitrary documents.
7 *
8 * @author drossiter
9 */
10 class DG_Thumber {
11
12 /**
13 * Returns the default mapping of thumber slug to whether it is active or not.
14 * @return array
15 */
16 public static function getDefaultThumbers() {
17 $gs_active = (bool)self::getGhostscriptExecutable();
18 $imagick_active = self::isImagickAvailable();
19
20 return array('av' => true, 'gs' => $gs_active,
21 'imagick' => $imagick_active, 'google' => false);
22 }
23
24 /**
25 * Wraps generation of thumbnails for various attachment filetypes.
26 *
27 * @param int $ID Document ID
28 * @param int $pg Page number to get thumb from.
29 * @return str URL to the thumbnail.
30 */
31 public static function getThumbnail($ID, $pg = 1) {
32 static $timeout = false;
33 if (false === $timeout) {
34 $timeout = time();
35 }
36
37 $options = self::getOptions();
38
39 // if we haven't saved a thumb, generate one
40 if (!isset($options['thumbs'][$ID])) {
41 // prevent page timing out -- generate for no more than 30 sec
42 if ((time() - $timeout) > 30) {
43 return self::getDefaultThumbnail($ID, $pg);
44 }
45
46 // do the processing
47 $file = get_attached_file($ID);
48
49 foreach (self::getThumbers() as $ext_preg => $thumber) {
50 $ext_preg = '!\.(' . $ext_preg . ')$!i';
51
52 if (preg_match($ext_preg, $file)
53 && ($thumb = self::getThumbnailTemplate($thumber, $ID, $pg))) {
54 $options['thumbs'][$ID] = array(
55 'created_timestamp' => time(),
56 'thumb_url' => $thumb['url'],
57 'thumb_path' => $thumb['path'],
58 'thumber' => $thumber
59 );
60 self::setOptions($options);
61 break;
62 }
63 }
64 }
65
66 if (!isset($options['thumbs'][$ID]) || false === $options['thumbs'][$ID]) {
67 if (!isset($options['thumbs'][$ID])) {
68 $options['thumbs'][$ID] = false;
69 self::setOptions($options);
70 }
71
72 // fallback to default thumb for attachment type
73 $url = self::getDefaultThumbnail($ID, $pg);
74 } else {
75 // use generated thumbnail
76 $url = $options['thumbs'][$ID]['thumb_url'];
77 }
78
79 return $url;
80 }
81
82 /*==========================================================================
83 * AUDIO VIDEO THUMBNAILS
84 *=========================================================================*/
85
86 /**
87 * Uses wp_read_video_metadata() and wp_read_audio_metadata() to retrieve
88 * an embedded image to use as a thumbnail.
89 *
90 * NOTE: Caller must verify that WP version >= 3.6.
91 *
92 * @param str $ID The attachment ID to retrieve thumbnail from.
93 * @param int $pg Unused.
94 * @return bool|str False on failure, URL to thumb on success.
95 */
96 public static function getAudioVideoThumbnail($ID, $pg = 1) {
97 if(!file_exists(WP_ADMIN_DIR . '/includes/media.php')) {
98 return false;
99 }
100
101 include_once WP_ADMIN_DIR . '/includes/media.php';
102
103 $attachment = get_post($ID);
104 $doc_path = get_attached_file($ID);
105
106 if (preg_match('#^video/#', get_post_mime_type($attachment))) {
107 $metadata = wp_read_video_metadata($doc_path);
108 }
109 elseif (preg_match('#^audio/#', get_post_mime_type($attachment))) {
110 $metadata = wp_read_audio_metadata($doc_path);
111 }
112
113 // unsupported mime type || no embedded image present
114 if(!isset($metadata) || empty($metadata['image']['data'])) {
115 return false;
116 }
117
118 $ext = 'jpg';
119 switch ($metadata['image']['mime']) {
120 case 'image/gif':
121 $ext = 'gif';
122 break;
123 case 'image/png':
124 $ext = 'png';
125 break;
126 }
127
128 $temp_file = self::getTempFile($ext);
129
130 if (!$fp = @fopen($temp_file, 'wb')) {
131 self::writeLog(__('Could not open file: ', 'document-gallery') . $temp_file);
132 return false;
133 }
134
135 if (!@fwrite($fp, $metadata['image']['data'])) {
136 self::writeLog(__('Could not write file: ', 'document-gallery') . $temp_file);
137 fclose($fp);
138 return false;
139 }
140
141 fclose($fp);
142
143 return $temp_file;
144 }
145
146 /**
147 * @return array All extensions supported by WP Audio Video Media metadata.
148 */
149 private static function getAudioVideoExts() {
150 return array_merge(wp_get_audio_extensions(), wp_get_video_extensions());
151 }
152
153 /*==========================================================================
154 * IMAGICK THUMBNAILS
155 *=========================================================================*/
156
157 /**
158 * Uses WP_Image_Editor_Imagick to generate thumbnails.
159 *
160 * @param int $ID The attachment ID to retrieve thumbnail from.
161 * @param int $pg The page to get the thumbnail of.
162 * @return bool|str False on failure, URL to thumb on success.
163 */
164 public static function getImagickThumbnail($ID, $pg = 1) {
165 include_once WP_INCLUDE_DIR . '/class-wp-image-editor.php';
166 include_once WP_INCLUDE_DIR . '/class-wp-image-editor-imagick.php';
167
168 $doc_path = get_attached_file($ID) . '[' . $pg - 1 . ']';
169
170 $img = new WP_Image_Editor_Imagick($doc_path);
171 $err = $img->load();
172 if(is_wp_error($err)) {
173 self::writeLog(
174 __('Failed to open file in Imagick: ', 'document-gallery') .
175 $err->get_error_message());
176 return false;
177 }
178
179 $temp_file = self::getTempFile();
180
181 $err = $img->save($temp_file, 'image/png');
182 if (is_wp_error($err)) {
183 self::writeLog(
184 __('Failed to save image in Imagick: ', 'document-gallery') .
185 $err->get_error_message());
186 return false;
187 }
188
189 return $temp_file;
190 }
191
192 /**
193 * @return bool Whether WP_Image_Editor_Imagick can be used on this system.
194 */
195 public static function isImagickAvailable() {
196 static $ret = null;
197
198 if (is_null($ret)) {
199 $ret = false;
200 if (file_exists(WP_INCLUDE_DIR . '/class-wp-image-editor-imagick.php')) {
201 include_once WP_INCLUDE_DIR . '/class-wp-image-editor.php';
202 include_once WP_INCLUDE_DIR . '/class-wp-image-editor-imagick.php';
203 $ret = WP_Image_Editor_Imagick::test();
204 }
205 }
206
207 return $ret;
208 }
209
210 /*==========================================================================
211 * GHOSTSCRIPT THUMBNAILS
212 *=========================================================================*/
213
214 /**
215 * Get thumbnail for document with given ID using Ghostscript. Imagick could
216 * also handle this, but is *much* slower.
217 *
218 * @param int $ID The attachment ID to retrieve thumbnail from.
219 * @param int $pg The page number to make thumbnail of -- index starts at 1.
220 * @return bool|str False on failure, URL to thumb on success.
221 */
222 public static function getGhostscriptThumbnail($ID, $pg = 1) {
223 static $gs = null;
224
225 if (is_null($gs)) {
226 $options = self::getOptions();
227 $gs = $options['gs'];
228 if (false !== $gs) {
229 $gs = "\"$gs\" -sDEVICE=png16m -dFirstPage=%d -dLastPage=%d"
230 . ' -dBATCH -dNOPAUSE -dPDFFitPage -sOutputFile=%s %s';
231 }
232 }
233
234 if (false === $gs) {
235 return false;
236 }
237
238 $doc_path = get_attached_file($ID);
239 $temp_path = self::getTempFile();
240
241 exec(sprintf($gs, $pg, $pg, $temp_path, $doc_path), $out, $ret);
242
243 if ($ret != 0) {
244 self::writeLog(__('Ghostscript failed: ', 'document-gallery') . print_r($out));
245 @unlink($temp_path);
246 return false;
247 }
248
249 return $temp_path;
250 }
251
252 /**
253 * @return array All extensions supported by Ghostscript.
254 */
255 private static function getGhostscriptExts() {
256 return array('pdf');
257 }
258
259 /**
260 * Checks whether we may call gs through exec().
261 *
262 * @return bool|str If available, returns exe path. False otherwise.
263 */
264 public static function getGhostscriptExecutable() {
265 static $executable = null;
266
267 if (is_null($executable)) {
268 // we must be able to exec()
269 $executable = self::isExecAvailable();
270 if (!$executable) return $executable;
271
272 // find on Windows system
273 if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
274 // look for environment variable
275 $executable = getenv('GSC');
276 if($executable) return $executable;
277
278 // hope GS in the path
279 $executable = exec('where gswin*c.exe');
280 if(!empty($executable)) return $executable;
281
282 // look directly in filesystem
283 // 64- or 32-bit binary
284 $executable = exec('dir /o:n/s/b "C:\Program Files\gs\*gswin*c.exe"');
285 if (!empty($executable)) {
286 return $executable;
287 }
288
289 // 32-bit binary on 64-bit OS
290 $executable = exec('dir /o:n/s/b "C:\Program Files (x86)\gs\*gswin32c.exe"');
291 $executable = empty($executable) ? false : $executable;
292 return $executable;
293 }
294
295 // this is why I use Linux...
296 $executable = exec('which gs');
297 $executable = empty($executable) ? false : $executable;
298 return $executable;
299 }
300
301 return $executable;
302 }
303
304 /*==========================================================================
305 * GOOGLE DRIVE VIEWER THUMBNAILS
306 *=========================================================================*/
307
308 /**
309 * Get thumbnail for document with given ID from Google Drive Viewer.
310 *
311 * NOTE: Caller must verify that extension is supported.
312 *
313 * @param str $ID The attachment ID to retrieve thumbnail for.
314 * @param int $pg The page number to make thumbnail of -- index starts at 1.
315 * @return bool|str False on failure, URL to thumb on success.
316 */
317 public static function getGoogleDriveThumbnail($ID_URL, $pg = 1) {
318 // User agent for Lynx 2.8.7rel.2 -- Why? Because I can.
319 static $user_agent = 'Lynx/2.8.7rel.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/1.0.0a';
320 static $timeout = 60;
321
322 $google_viewer = 'https://docs.google.com/viewer?url=%s&a=bi&pagenumber=%d&w=%d';
323 $doc_url = wp_get_attachment_url($ID_URL);
324 if (!$doc_url) {
325 return false;
326 }
327
328 $temp_file = self::getTempFile();
329
330 // args for use in HTTP request
331 $args = array(
332 'timeout' => $timeout, // these requests can take a LONG time
333 'redirection' => 5,
334 'httpversion' => '1.0',
335 'user-agent' => $user_agent,
336 'blocking' => true,
337 'headers' => array(),
338 'cookies' => array(),
339 'body' => null,
340 'compress' => false,
341 'decompress' => true,
342 'sslverify' => true,
343 'stream' => true,
344 'filename' => $temp_file
345 );
346
347 // prevent PHP timeout before HTTP completes
348 set_time_limit($timeout);
349
350 $options = self::getOptions();
351 $google_viewer = sprintf($google_viewer, urlencode($doc_url), (int)$pg, $options['width']);
352
353 // get thumbnail from Google Drive Viewer & check for error on return
354 $response = wp_remote_get($google_viewer, $args);
355
356 if (is_wp_error($response) || !preg_match('/[23][0-9]{2}/', $response['response']['code'])) {
357 self::writeLog(__('Failed to retrieve thumbnail from Google: ', 'document-gallery') .
358 (is_wp_error($response)
359 ? $response->get_error_message()
360 : $response['response']['message']));
361
362 @unlink($temp_file);
363 return false;
364 }
365
366 return $temp_file;
367 }
368
369 /**
370 * @return array All extensions supported by Google Drive Viewer.
371 */
372 private static function getGoogleDriveExts() {
373 return array(
374 'tiff', 'bmp', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
375 'pdf', 'pages', 'ai', 'psd', 'dxf', 'svg', 'eps', 'ps', 'ttf'
376 );
377 }
378
379 /**
380 * TODO: Currently always returns true.
381 * @return bool Whether Google Drive can access files on this system.
382 */
383 public static function isGoogleDriveAvailable() {
384 return true;
385 }
386
387 /*==========================================================================
388 * DEFAULT THUMBNAILS
389 *=========================================================================*/
390
391 /**
392 * Get thumbnail for document with given ID from default images.
393 *
394 * @param str $ID The attachment ID to retrieve thumbnail from.
395 * @param int $pg Unused.
396 * @return str URL to thumbnail.
397 */
398 public static function getDefaultThumbnail($ID, $pg = 1) {
399 $icon_url = DG_URL . 'assets/icons/';
400
401 $url = wp_get_attachment_url($ID);
402 $ext = self::getExt($url);
403
404 // handle images
405 if (wp_attachment_is_image($ID) &&
406 ($icon = wp_get_attachment_image_src($ID, 'thumbnail', false))) {
407 $icon = $icon[0];
408 }
409 // default extension icon
410 elseif ($name = self::getDefaultIcon($ext)) {
411 $icon = $icon_url . $name;
412 }
413 // fallback to standard WP icons
414 elseif ($icon = wp_get_attachment_image_src($ID, null, true)) {
415 $icon = $icon[0];
416 }
417 // everything failed. This is bad...
418 else {
419 $icon = $icon_url . 'missing.png';
420 }
421
422 return $icon;
423 }
424
425 /**
426 * Returns the name of the image to represent the filetype given.
427 *
428 * @param str $ext
429 * @return str
430 */
431 private static function getDefaultIcon($ext) {
432 // Maps file ext to default image name.
433 static $exts = array(
434 // Most Common First
435 'pdf' => 'pdf.png',
436
437 // MS Office
438 'doc|docx|docm|dotx|dotm' => 'msdoc.png',
439 'ppt|pot|pps|pptx|pptm|ppsx|ppsm|potx|potm|ppam|sldx|sldm' => 'msppt.png',
440 'xla|xls|xlt|xlw|xlsx|xlsm|xlsb|xltx|xltm|xlam' => 'msxls.png',
441 'mdb' => 'msaccess.png',
442
443 // iWork
444 'key' => 'key.png',
445 'numbers' => 'numbers.png',
446 'pages' => 'pages.png',
447
448 // Images
449 'jpg|jpeg|jpe|gif|png|bmp|tif|tiff|ico' => 'image.png',
450
451 // Video formats
452 'asf|asx|wmv|wmx|wm|avi|divx|flv|mov' => 'video.png',
453 'qt|mpeg|mpg|mpe|mp4|m4v|ogv|webm|mkv' => 'video.png',
454
455 // Audio formats
456 'mp3|m4a|m4b|ra|ram|wav|ogg|oga|wma|wax|mka' => 'audio.png',
457 'midi|mid' => 'midi.png',
458
459 // Text formats
460 'txt|tsv|csv' => 'text.png',
461 'rtx' => 'rtx.png',
462 'rtf' => 'rtf.png',
463 'ics' => 'ics.png',
464 'wp|wpd' => 'wordperfect.png',
465
466 // Programming
467 'html|htm' => 'html.png',
468 'css' => 'css.png',
469 'js' => 'javascript.png',
470 'class' => 'java.png',
471 'asc' => 'asc.png',
472 'c' => 'c.png',
473 'cc|cpp' => 'cpp.png',
474 'h' => 'h.png',
475
476 // Msc application formats
477 'zip|tar|gzip|gz|bz2|tgz|7z|rar' => 'compressed.png',
478 'exe' => 'exec.png',
479 'swf' => 'shockwave.png',
480
481 // OpenDocument formats
482 'odt' => 'opendocument-text.png',
483 'odp' => 'opendocument-presentation.png',
484 'ods' => 'opendocument-spreadsheet.png',
485 'odg' => 'opendocument-graphics.png',
486 'odb' => 'opendocument-database.png',
487 'odf' => 'opendocument-formula.png'
488 );
489
490 foreach ($exts as $ext_preg => $icon) {
491 $ext_preg = '!(' . $ext_preg . ')$!i';
492 if (preg_match($ext_preg, $ext)) {
493 return $icon;
494 }
495 }
496
497 return false;
498 }
499
500 /*==========================================================================
501 * GENERAL THUMBNAIL HELPER FUNCTIONS
502 *=========================================================================*/
503
504 /**
505 * @return array WP_Post objects for each attachment that has been processed.
506 */
507 public static function getThumbed() {
508 $options = self::getOptions();
509 $args = array(
510 'post_type' => 'attachment',
511 'post_status' => 'inherit',
512 'post_per_page' => -1,
513 'post__in' => array_keys($options['thumbs'])
514 );
515
516 return count($args['post__in']) ? get_posts($args) : array();
517 }
518
519 /**
520 * Key: Attachment ID
521 * Val: array
522 * + created_timestamp - When the thumbnail was generated.
523 * + thumb_path - System path to thumbnail image.
524 * + thumb_url - URL pointing to the thumbnail for this document.
525 * + thumber - Generator used to create thumb OR false if failed to gen.
526 * @return array Thumber options from DB.
527 */
528 public static function getOptions() {
529 global $dg_options;
530 return $dg_options['thumber'];
531 }
532
533 /**
534 * Key: Attachment ID
535 * Val: array
536 * + created_timestamp - When the thumbnail was generated.
537 * + thumb_path - System path to thumbnail image.
538 * + thumb_url - URL pointing to the thumbnail for this document.
539 * + thumber - Generator used to create thumb OR false if failed to gen.
540 * @param array $options Thumber options to store in DB
541 */
542 private static function setOptions($options) {
543 global $dg_options;
544 $dg_options['thumber'] = $options;
545 update_option(DG_OPTION_NAME, $dg_options);
546 }
547
548 /**
549 * @filter dg_thumbers Allows developers to filter the Thumbers used
550 * for specific filetypes. Index is the regex to match file extensions
551 * supported and the value is anything that can be accepted by call_user_func().
552 * The function must take two parameters, 1st is the int ID of the attachment
553 * to get a thumbnail for, 2nd is the page to take a thumbnail of
554 * (may not be relevant for some filetypes).
555 *
556 * @return array
557 */
558 private static function getThumbers() {
559 static $thumbers = false;
560
561 if (false === $thumbers) {
562 global $wp_version;
563 $options = self::getOptions();
564 $active = $options['active'];
565 $thumbers = array();
566
567 // Audio/Video embedded images
568 if ($active['av'] && version_compare($wp_version, '3.6', '>=')) {
569 $exts = implode('|', self::getAudioVideoExts());
570 $thumbers[$exts] = array(__CLASS__, 'getAudioVideoThumbnail');
571 }
572
573 // Ghostscript
574 if ($active['gs'] && false !== self::getGhostscriptExecutable()) {
575 $exts = implode('|', self::getGhostscriptExts());
576 $thumbers[$exts] = array(__CLASS__, 'getGhostscriptThumbnail');
577 }
578
579 // Imagick
580 if ($active['imagick'] && self::isImagickAvailable()) {
581 include_once WP_INCLUDE_DIR . '/class-wp-image-editor.php';
582 include_once WP_INCLUDE_DIR . '/class-wp-image-editor-imagick.php';
583 try {
584 $exts = @Imagick::queryFormats();
585 if($exts) {
586 $exts = implode('|', $exts);
587 $thumbers[$exts] = array(__CLASS__, 'getImagickThumbnail');
588 }
589 }
590 catch (Exception $e) {
591
592 }
593 }
594
595 // Google Drive Viewer
596 if ($active['google']) {
597 $exts = implode('|', self::getGoogleDriveExts());
598 $thumbers[$exts] = array(__CLASS__, 'getGoogleDriveThumbnail');
599 }
600
601 // allow users to filter thumbers used
602 $thumbers = apply_filters('dg_thumbers', $thumbers);
603
604 // strip out anything that can't be called
605 $thumbers = array_filter($thumbers, 'is_callable');
606 }
607
608 return $thumbers;
609 }
610
611 /**
612 * Template that handles generating a thumbnail.
613 *
614 * @param callable $generator Takes ID and pg and returns path to temp file or false.
615 * @param int $ID ID for the attachment that we need a thumbnail for.
616 * @param int $pg Page number of the attachment to get a thumbnail for.
617 * @return bool|array Array containing 'url' and 'path' values or false.
618 */
619 public static function getThumbnailTemplate($generator, $ID, $pg = 1) {
620 // delegate thumbnail generation to $generator
621 if (false === ($temp_path = call_user_func($generator, $ID, $pg))) {
622 return false;
623 }
624
625 // get some useful stuff
626 $doc_path = get_attached_file($ID);
627 $doc_url = wp_get_attachment_url($ID);
628 $dirname = dirname($doc_path);
629 $basename = basename($doc_path);
630 if (false === ($len = strrpos($basename, '.'))) {
631 $len = strlen($basename);
632 }
633 $extless = substr($basename, 0, $len);
634 $ext = self::getExt($temp_path);
635
636 $thumb_name = self::getUniqueThumbName($dirname, $extless, $ext);
637 $thumb_path = $dirname . DIRECTORY_SEPARATOR . $thumb_name;
638
639 // scale generated image down
640 $img = wp_get_image_editor($temp_path);
641
642 if (is_wp_error($img)) {
643 self::writeLog(
644 __('Failed to get image editor: ', 'document-gallery') .
645 $img->get_error_message());
646 return false;
647 }
648
649 $options = self::getOptions();
650 $img->resize($options['width'], $options['height'], false);
651 $err = $img->save($thumb_path);
652
653 if (is_wp_error($err)) {
654 self::writeLog(
655 __('Failed to save image: ', 'document-gallery') .
656 $err->get_error_message());
657 return false;
658 }
659
660 // do some cleanup
661 @unlink($temp_path);
662 self::deleteThumbMeta($ID);
663
664 return array(
665 'path' => $thumb_path,
666 'url' => preg_replace('#'.preg_quote($basename).'$#', $thumb_name, $doc_url));
667 }
668
669 /**
670 * Caller should handle removal of the temp file when finished.
671 *
672 * @staticvar int $count
673 * @param str $ext
674 */
675 private static function getTempFile($ext = 'png') {
676 static $base = null;
677 static $tmp;
678
679 if (is_null($base)) {
680 $base = md5(time());
681 $tmp = untrailingslashit(get_temp_dir());
682 }
683
684 return $tmp . DIRECTORY_SEPARATOR . wp_unique_filename($tmp, "$base.$ext");
685 }
686
687 /**
688 * Constructs name for file's thumbnail, ensuring that it does not conflict
689 * with any existing file.
690 *
691 * @param str $dirname Directory where the document is located.
692 * @param str $extless Base name, less the extension.
693 * @param str $ext The extension of the image to be created.
694 * @return str Name unique within the directory given, derived from the basename given.
695 */
696 private static function getUniqueThumbName($dirname, $extless, $ext = 'png') {
697 return wp_unique_filename($dirname, str_replace('.', '-', $extless) . '-thumb.' . $ext);
698 }
699
700 /**
701 * Removes the existing thumbnail/document meta for the attachment
702 * with $ID, if such a thumbnail exists.
703 *
704 * @param int $ID
705 */
706 public static function deleteThumbMeta($ID) {
707 $options = self::getOptions();
708
709 if (isset($options['thumbs'][$ID])) {
710 if (false !== $options['thumbs'][$ID]) {
711 @unlink($options['thumbs'][$ID]['thumb_path']);
712 }
713
714 unset($options['thumbs'][$ID]);
715 self::setOptions($options);
716 }
717 }
718
719 /**
720 * Checks whether exec() may be used.
721 * Source: http://stackoverflow.com/a/12980534/866618
722 *
723 * @return bool Whether exec() is available.
724 */
725 public static function isExecAvailable() {
726 static $available = null;
727
728 if (is_null($available)) {
729 $available = true;
730
731 if (ini_get('safe_mode')) {
732 $available = false;
733 } else {
734 $d = ini_get('disable_functions');
735 $s = ini_get('suhosin.executor.func.blacklist');
736 if ("$d$s") {
737 $array = preg_split('/,\s*/', "$d,$s");
738 $available = !in_array('exec', $array);
739 }
740 }
741 }
742
743 return $available;
744 }
745
746 /**
747 * Formerly achieved with wp_check_filetype(), but it was only returning
748 * valid results if the active user had permission to upload the given filetype.
749 *
750 * @param str $filename Name of the file to get extension from.
751 * @return str|bool Returns the file extension on success, false on failure.
752 */
753 private static function getExt($filename) {
754 foreach (wp_get_mime_types() as $ext_preg => $unused) {
755 $ext_preg = '!\.(' . $ext_preg . ')$!i';
756 if (preg_match($ext_preg, $filename, $ext_matches)) {
757 return $ext_matches[1];
758 }
759 }
760
761 return false;
762 }
763
764 /**
765 * Appends error log with $entry if WordPress is in debug mode.
766 *
767 * @param str $entry
768 */
769 private static function writeLog($entry) {
770 if (defined('WP_DEBUG') && WP_DEBUG) {
771 $err = 'DG: ' . print_r($entry, true) . PHP_EOL;
772 if (defined('ERRORLOGFILE')) {
773 error_log($err, 3, ERRORLOGFILE);
774 } else {
775 error_log($err);
776 }
777 }
778 }
779
780 /**
781 * Blocks instantiation. All functions are static.
782 */
783 private function __construct() {
784
785 }
786 }
787
788 ?>