/**
  * Initialize the thumber class for use in thumbnail generation.
  *
  * @return DG_AbstractThumber The instance for the calling class.
  */
 public static function init()
 {
     $class = get_called_class();
     if (!isset(self::$instances[$class])) {
         try {
             self::$instances[$class] = new static();
             add_action('dg_thumbers', array($class, 'thumbersFilter'), 0);
         } catch (Exception $e) {
             DG_Logger::writeLog(DG_LogLevel::Error, "Failed to construct thumber of type {$class}.");
         }
     }
     return isset(self::$instances[$class]) ? self::$instances[$class] : null;
 }
 /**
  * Uses WP_Image_Editor_Imagick to generate thumbnails.
  *
  * @param int $ID The attachment ID to retrieve thumbnail from.
  * @param int $pg The page to get the thumbnail of.
  *
  * @return bool|string  False on failure, URL to thumb on success.
  */
 public function getThumbnail($ID, $pg = 1)
 {
     $doc_path = get_attached_file($ID);
     $img = new DG_Image_Editor_Imagick($doc_path, $pg - 1);
     $err = $img->load();
     if (is_wp_error($err)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to open file in Imagick: ', 'document-gallery') . $err->get_error_message());
         return false;
     }
     $temp_file = DG_Util::getTempFile();
     $err = $img->save($temp_file, 'image/png');
     if (is_wp_error($err)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to save image in Imagick: ', 'document-gallery') . $err->get_error_message());
         return false;
     }
     return $temp_file;
 }
 /**
  * Loads the filepath into Imagick object.
  */
 public function load()
 {
     $ret = parent::load();
     // set correct page number
     if (!is_null($this->pg) && !is_wp_error($ret) && is_callable(array($this->image, 'setIteratorIndex'))) {
         $err = __('Failed to set Imagick page number', 'document-gallery');
         // setIteratorIndex() should return false on failure, but I've found
         // reports of it throwing an error so handling both cases.
         // NOTE: I've also seen it fail and return true, so we may not
         // log anything on failure...
         try {
             if (!$this->image->setIteratorIndex($this->pg)) {
                 DG_Logger::writeLog(DG_LogLevel::Error, $err . '.');
             }
         } catch (Exception $e) {
             DG_Logger::writeLog(DG_LogLevel::Error, $err . ': ' . $e->getMessage());
         }
     }
     return $ret;
 }
 /**
  * @param int $ID The attachment ID.
  * @param int $pg The page to thumbnail.
  *
  * @return bool Always false. Asynchronously set the thumbnail in webhook later.
  */
 public function getThumbnail($ID, $pg = 1)
 {
     global $dg_options;
     include_once DG_PATH . 'inc/thumbers/thumber-co/thumber-client/client.php';
     include_once DG_PATH . 'inc/thumbers/thumber-co/thumber-client/thumb-request.php';
     $options = DG_Thumber::getOptions();
     $url_or_path = get_attached_file($ID);
     if (!self::checkGeometry($options['width'], $options['height'])) {
         DG_Logger::writeLog(DG_LogLevel::Detail, "Skipping attachment #{$ID} as it exceeds Thumber.co subscription geometry limit.");
         return false;
     }
     if (!self::checkFileSize($url_or_path)) {
         DG_Logger::writeLog(DG_LogLevel::Detail, "Skipping attachment #{$ID} as it exceeds Thumber.co subscription file size limit.");
         return false;
     }
     $mime_type = get_post_mime_type($ID);
     if (!$dg_options['thumber-co']['direct_upload']) {
         $url_or_path = wp_get_attachment_url($ID);
     }
     if (!$url_or_path || !$mime_type) {
         return false;
     }
     $req = new ThumberThumbReq();
     $req->setCallback(self::$webhook);
     $req->setMimeType($mime_type);
     $req->setNonce($ID . self::NonceSeparator . md5(microtime()));
     $req->setPg($pg);
     $req->setGeometry($options['width'] . 'x' . $options['height']);
     if ($dg_options['thumber-co']['direct_upload']) {
         $req->setDecodedData(file_get_contents($url_or_path));
     } else {
         $req->setUrl($url_or_path);
     }
     $resp = self::$client->sendThumbRequest($req);
     if ($resp['http_code'] < 200 || $resp['http_code'] > 399) {
         DG_Logger::writeLog(DG_LogLevel::Error, 'Failed to transmit to server: ' . $resp['body']);
     }
     // always returns false -- we set the thumbnail later when webhook is hit
     return false;
 }
 /**
  * Sanitize the given key/value pair, passing any error to $errs if given.
  *
  * @param string $key The key to reference the current value in the defaults array.
  * @param mixed $value The value to be sanitized.
  * @param string[] $errs The array of errors, which will be appended with any errors found.
  *
  * @return mixed The sanitized value, falling back to the current default value when invalid value given.
  */
 public static function sanitizeParameter($key, $value, &$errs = null)
 {
     // all sanitize methods must be in the following form: sanitize<UpperCamelCaseKey>
     $funct = $key;
     $funct[0] = strtoupper($funct[0]);
     $funct = 'sanitize' . preg_replace_callback('/_([a-z])/', array(__CLASS__, 'secondCharToUpper'), $funct);
     $callable = array(__CLASS__, $funct);
     // avoid looking for method beforehand unless we're running in debug mode -- expensive call
     if (DG_Logger::logEnabled() && !method_exists(__CLASS__, $funct)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Attempted to call invalid function: ', 'document-gallery') . implode('::', $callable), true);
     }
     // call param-specific sanitization
     $ret = call_user_func_array($callable, array($value, &$err));
     // check for error and return default
     if (isset($err)) {
         $defaults = DG_Gallery::getOptions();
         $ret = $defaults[$key];
         if (!is_null($errs)) {
             $errs[$key] = $err;
         }
     }
     return $ret;
 }
 /**
  * Get thumbnail for document with given ID using Ghostscript. Imagick could
  * also handle this, but is *much* slower.
  *
  * @param int $ID The attachment ID to retrieve thumbnail from.
  * @param int $pg The page number to make thumbnail of -- index starts at 1.
  *
  * @return bool|string  False on failure, URL to thumb on success.
  */
 public function getThumbnail($ID, $pg = 1)
 {
     static $gs = null;
     if (is_null($gs)) {
         $options = DG_Thumber::getOptions();
         $gs = $options['gs'];
         if (false !== $gs) {
             $gs = escapeshellarg($gs) . ' -sDEVICE=png16m -dFirstPage=%1$d' . ' -dLastPage=%1$d -dBATCH -dNOPAUSE -dPDFFitPage -sOutputFile=%2$s %3$s 2>&1';
         }
     }
     if (false === $gs) {
         return false;
     }
     $doc_path = get_attached_file($ID);
     $temp_path = DG_Util::getTempFile();
     exec(sprintf($gs, $pg, $temp_path, $doc_path), $out, $ret);
     if ($ret != 0) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Ghostscript failed: ', 'document-gallery') . print_r($out));
         @unlink($temp_path);
         return false;
     }
     return $temp_path;
 }
 /**
  * Uses wp_read_video_metadata() and wp_read_audio_metadata() to retrieve
  * an embedded image to use as a thumbnail.
  *
  * @param string $ID The attachment ID to retrieve thumbnail from.
  * @param int $pg Unused.
  *
  * @return bool|string  False on failure, URL to thumb on success.
  */
 public function getThumbnail($ID, $pg = 1)
 {
     include_once DG_WPADMIN_PATH . 'includes/media.php';
     $doc_path = get_attached_file($ID);
     $mime_type = get_post_mime_type($ID);
     if (DG_Util::startsWith($mime_type, 'video/')) {
         $metadata = wp_read_video_metadata($doc_path);
     } elseif (DG_Util::startsWith($mime_type, 'audio/')) {
         $metadata = wp_read_audio_metadata($doc_path);
     }
     // unsupported mime type || no embedded image present
     if (!isset($metadata) || empty($metadata['image']['data'])) {
         return false;
     }
     $ext = 'jpg';
     switch ($metadata['image']['mime']) {
         case 'image/gif':
             $ext = 'gif';
             break;
         case 'image/png':
             $ext = 'png';
             break;
     }
     $temp_file = DG_Util::getTempFile($ext);
     if (!($fp = @fopen($temp_file, 'wb'))) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Could not open file: ', 'document-gallery') . $temp_file);
         return false;
     }
     if (!@fwrite($fp, $metadata['image']['data'])) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Could not write file: ', 'document-gallery') . $temp_file);
         fclose($fp);
         return false;
     }
     fclose($fp);
     return $temp_file;
 }
 /**
  * @param $err string Fires on fatal error.
  */
 protected function handleError($err)
 {
     DG_Logger::writeLog(DG_LogLevel::Error, $err);
 }
 /**
  * Initializes the thumbs variable if not already initialized.
  */
 private static function initThumbs()
 {
     if (!isset(self::$thumbs)) {
         DG_Logger::writeLog(DG_LogLevel::Detail, 'Populating thumbnail cache.');
         global $wpdb;
         self::$thumbs = array();
         $meta_key = self::$meta_key;
         $sql = "SELECT post_id, meta_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = '{$meta_key}'";
         foreach ($wpdb->get_results($sql) as $row) {
             $key = $row->post_id;
             $new = new DG_Thumb($row);
             if (!isset(self::$thumbs[$key])) {
                 self::$thumbs[$key] = array();
             } elseif (isset(self::$thumbs[$key][$new->dimensions])) {
                 // it is possible to end up with duplicate thumbnails -- cleanup here
                 $old = self::$thumbs[$key][$new->dimensions];
                 if ($old->timestamp < $new->timestamp) {
                     $old->delete();
                 } else {
                     $new->delete();
                     continue;
                 }
             }
             self::$thumbs[$key][$new->dimensions] = $new;
         }
     }
 }
    /**
     * Render the Logging table.
     */
    public static function renderLoggingSection()
    {
        $log_list = DG_Logger::readLog();
        if ($log_list) {
            $levels = array_map(array(__CLASS__, 'getLogLabelSpan'), array_keys(DG_LogLevel::getLogLevels()));
            $fmt = '<tr>' . '<th scope="col" class="manage-column column-date sorted desc"><a href="javascript:void(0);">' . '<span>%s</span><span class="sorting-indicator"></span></a>' . '</th>' . '<th scope="col" class="manage-column column-level"><span>%s</span></th>' . '<th scope="col" class="manage-column column-message"><span>%s</span></th>' . '</tr>';
            $thead = sprintf($fmt, __('Date', 'document-gallery'), __('Level', 'document-gallery'), __('Message', 'document-gallery'));
            ?>
			<div class="log-list-wrapper">
				<div>
					<div class="tablenav top">
						<div class="alignleft bulkactions">
							<button class="action expandAll">
								<?php 
            echo __('Expand All', 'document-gallery');
            ?>
							</button>
							<button class="action collapseAll">
								<?php 
            echo __('Collapse All', 'document-gallery');
            ?>
							</button>
						</div>
						<div class="levelSelector">
							<input type="checkbox" id="allLevels" name="lswitch" value="all" checked/>
							<label for="allLevels" class="allLevels">ALL</label>
							<?php 
            foreach (array_keys(DG_LogLevel::getLogLevels()) as $k) {
                ?>
								<?php 
                $lower = strtolower($k);
                $upper = strtoupper($k);
                ?>
								<input type="checkbox" id="<?php 
                echo $lower;
                ?>
Level" name="lswitch"
								       value="<?php 
                echo $lower;
                ?>
" checked/>
								<label for="<?php 
                echo $lower;
                ?>
Level"
								       class="<?php 
                echo $lower;
                ?>
Level"><?php 
                echo $upper;
                ?>
</label>
							<?php 
            }
            ?>
						</div>
					</div>
					<table id="LogTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">
						<thead>
						<?php 
            echo $thead;
            ?>
						</thead>
						<tfoot>
						<?php 
            echo $thead;
            ?>
						</tfoot>
						<tbody><?php 
            for ($i = count($log_list); $i > 0; $i--) {
                $log_entry = $log_list[$i - 1];
                $date = DocumentGallery::localDateTimeFromTimestamp($log_entry[0]);
                // convert attachment names to links
                $log_entry[2] = preg_replace('/[ ^](attachment #)(\\d+)[.,: ]/i', ' <a href="' . home_url() . '/?attachment_id=\\2" target="_blank">\\1<strong>\\2</strong></a> ', $log_entry[2]);
                // bold the place where log entry was submitted
                $log_entry[2] = preg_replace('/^(\\((?:\\w+(?:::|->))?\\w+\\)) /', '<strong>\\1</strong> ', $log_entry[2]);
                // italicize any function references within log entry
                $log_entry[2] = preg_replace('/(\\(?\\w+(?:::|->)\\w+\\)?)/m', '<i>\\1</i>', $log_entry[2]);
                echo '<tr><td class="date column-date" data-sort-value="' . $log_entry[0] . '"><span class="logLabel date">' . $date . '</span></td>' . '<td class="column-level">' . $levels[$log_entry[1]] . '</td>' . '<td class="column-entry">' . (empty($log_entry[3]) ? '<pre>' . $log_entry[2] . '</pre>' : '<div class="expander" title="Click to Expand"><pre>' . $log_entry[2] . '</pre><div><span class="dashicons dashicons-arrow-down-alt2"></span></div></div><div class="spoiler-body"><pre>' . $log_entry[3] . '</pre></div>') . '</td>' . '</tr>' . PHP_EOL;
            }
            ?>
						</tbody>
					</table>
					<div class="tablenav bottom">
						<div class="alignright bulkactions">
							<button class="button action clearLog" name='<?php 
            echo DG_OPTION_NAME;
            ?>
[clearLog]'
							        value='true'>
								<?php 
            echo __('Clear Log', 'document-gallery');
            ?>
							</button>
						</div>
					</div>
				</div>
			</div>
		<?php 
        } else {
            echo '<div class="noLog">' . __('There are no log entries at this time.', 'document-gallery') . '<br />' . __('For Your information:', 'document-gallery') . ' <strong><i>' . __('Logging', 'document-gallery') . '</i></strong> ' . (DG_Logger::logEnabled() ? '<span class="loggingON">' . __('is turned ON', 'document-gallery') . '!</span>' : '<span class="loggingOFF">' . __('is turned OFF', 'document-gallery') . '!</span>') . '</div>';
        }
    }
Example #11
0
 /**
  * Template that handles generating a thumbnail.
  *
  * If image has already been generated through other means, $pg may be set to the system path where the
  * thumbnail is located. In this case, $generator will not be invoked, but *will* be kept for historical purposes.
  *
  * @param callable $generator Takes ID and pg and returns path to temp file or false.
  * @param int $ID ID for the attachment that we need a thumbnail for.
  * @param int|string $pg Page number of the attachment to get a thumbnail for or the system path to the image to be used.
  *
  * @return bool        Whether generation was successful.
  */
 private static function thumbnailGenerationHarness($generator, $ID, $pg = 1)
 {
     // handle system page in $pg variable
     if (is_string($pg) && !is_numeric($pg)) {
         $temp_path = $pg;
     } elseif (false === ($temp_path = call_user_func($generator, $ID, $pg))) {
         return false;
     }
     // get some useful stuff
     $doc_path = get_attached_file($ID);
     $doc_url = wp_get_attachment_url($ID);
     $dirname = dirname($doc_path);
     $basename = basename($doc_path);
     if (false === ($len = strrpos($basename, '.'))) {
         $len = strlen($basename);
     }
     $extless = substr($basename, 0, $len);
     $ext = self::getExt($temp_path);
     $thumb_name = self::getUniqueThumbName($dirname, $extless, $ext);
     $thumb_path = $dirname . DIRECTORY_SEPARATOR . $thumb_name;
     // scale generated image down
     $img = wp_get_image_editor($temp_path);
     if (is_wp_error($img)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to get image editor: ', 'document-gallery') . $img->get_error_message());
         return false;
     }
     $options = self::getOptions();
     $img->resize($options['width'], $options['height'], false);
     $err = $img->save($thumb_path);
     if (is_wp_error($err)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to save image: ', 'document-gallery') . $err->get_error_message());
         return false;
     }
     // do some cleanup
     @unlink($temp_path);
     self::deleteThumbMeta($ID);
     // store new thumbnail in DG options
     $options['thumbs'][$ID] = array('timestamp' => time(), 'thumb_url' => preg_replace('#' . preg_quote($basename) . '$#', $thumb_name, $doc_url), 'thumb_path' => $thumb_path, 'thumber' => $generator);
     self::setOptions($options);
     return true;
 }
 /**
  * Removes the validation option. Validation is now non-optional.
  *
  * @param mixed[][] $options The options to be modified.
  */
 private static function threePointFour(&$options)
 {
     if (version_compare($options['meta']['version'], '3.4', '<')) {
         unset($options['validation']);
         if (!DocumentGallery::isValidOptionsStructure($options)) {
             DG_Logger::writeLog(DG_LogLevel::Error, 'Found invalid options structure. Reverting to default options.', false, true);
             $options = self::getDefaultOptions();
         }
     }
 }
 /**
  * Validates uploaded file as a semi for potential thumbnail.
  *
  * @param  string $var File field name.
  *
  * @return bool|string   False on failure, path to temp file on success.
  */
 public static function validateUploadedFile($var = 'file')
 {
     // checking if any file was delivered
     if (!isset($_FILES[$var])) {
         return false;
     }
     // we gonna process only first one
     if (!is_array($_FILES[$var]['error'])) {
         $upload_err = $_FILES[$var]['error'];
         $upload_path = $_FILES[$var]['tmp_name'];
         $upload_size = $_FILES[$var]['size'];
         $upload_type = $_FILES[$var]['type'];
         $upload_name = $_FILES[$var]['name'];
     } else {
         $upload_err = $_FILES[$var]['error'][0];
         $upload_path = $_FILES[$var]['tmp_name'][0];
         $upload_size = $_FILES[$var]['size'][0];
         $upload_type = $_FILES[$var]['type'][0];
         $upload_name = $_FILES[$var]['name'][0];
     }
     $info = getimagesize($upload_path);
     if ($info) {
         if ($info['mime'] !== $upload_type) {
             // in DG_Thumber::getExt() we'll define and set appropriate extension
             DG_Logger::writeLog(DG_LogLevel::Warning, __('File extension doesn\'t match the MIME type of the image: ', 'document-gallery') . $upload_name . ' - ' . $info['mime']);
         }
         if ($upload_size > wp_max_upload_size()) {
             DG_Logger::writeLog(DG_LogLevel::Warning, __('Uploaded file size exceeds the allowable limit: ', 'document-gallery') . $upload_name . ' - ' . $upload_size . 'b');
             return false;
         }
     } else {
         DG_Logger::writeLog(DG_LogLevel::Warning, __('Uploaded file is not an image: ', 'document-gallery') . $upload_name);
         return false;
     }
     if ($upload_err == UPLOAD_ERR_OK && $upload_size > 0) {
         $temp_file = $upload_path;
     } else {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to get uploaded file: ', 'document-gallery') . $upload_err);
         return false;
     }
     return $temp_file;
 }
 /**
  * Template that handles generating a thumbnail.
  *
  * If image has already been generated through other means, $pg may be set to the system path where the
  * thumbnail is located. In this case, $generator will not be invoked, but *will* be kept for historical purposes.
  *
  * @param DG_AbstractThumber|string $generator Takes ID and pg and returns path to temp file or false.
  * @param int $ID ID for the attachment that we need a thumbnail for.
  * @param int|string $pg Page number of the attachment to get a thumbnail for or the system path to the image to be used.
  *
  * @return DG_Thumb|bool The generated thumbnail or false on failure.
  */
 private static function thumbnailGenerationHarness($generator, $ID, $pg = 1)
 {
     // handle system page in $pg variable
     if (is_string($pg) && !is_numeric($pg)) {
         $temp_path = $pg;
     } elseif (is_a($generator, 'DG_AbstractThumber')) {
         // delegate thumbnail generation to $generator
         if (false === ($temp_path = $generator->getThumbnail($ID, $pg))) {
             return false;
         }
         // NOTE: get string representation to be stored with thumb in DB
         $generator = get_class($generator);
     } else {
         DG_Logger::writeLog(DG_LogLevel::Error, 'Attempted to call thumbnailGenerationHarness with invalid generator: ' . print_r($generator, true));
         return false;
     }
     // get some useful stuff
     $doc_path = get_attached_file($ID);
     $dirname = dirname($doc_path);
     $basename = basename($doc_path);
     if (false === ($len = strrpos($basename, '.'))) {
         $len = strlen($basename);
     }
     $extless = substr($basename, 0, $len);
     $ext = self::getExt($temp_path);
     $thumb_name = self::getUniqueThumbName($dirname, $extless, $ext);
     $thumb_path = "{$dirname}/{$thumb_name}";
     // scale generated image down
     $img = wp_get_image_editor($temp_path);
     if (is_wp_error($img)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to get image editor: ', 'document-gallery') . $img->get_error_message());
         return false;
     }
     $options = self::getOptions();
     $img->resize($options['width'], $options['height'], false);
     $err = $img->save($thumb_path);
     if (is_wp_error($err)) {
         DG_Logger::writeLog(DG_LogLevel::Error, __('Failed to save image: ', 'document-gallery') . $err->get_error_message());
         return false;
     }
     // do some cleanup
     @unlink($temp_path);
     // save new thumb
     DG_Logger::writeLog(DG_LogLevel::Detail, 'Creating thumb object.');
     $upload = wp_upload_dir();
     $thumb = new DG_Thumb();
     $thumb->setPostId($ID);
     $thumb->setDimensions($options['width'] . 'x' . $options['height']);
     $thumb->setTimestamp(time());
     $thumb->setRelativePath(substr($thumb_path, strlen($upload['basedir']) + 1));
     $thumb->setGenerator($generator);
     $thumb->save();
     return $thumb;
 }
 /**
  * Checks whether the given options match the option schema.
  *
  * @param mixed[] $new The new options to be validated.
  * @param mixed[] $old The old options.
  *
  * @return mixed[] The options to be saved.
  */
 public static function validateOptionsStructure($new, $old)
 {
     if (self::isValidOptionsStructure($new)) {
         $ret = $new;
     } else {
         $ret = $old;
         DG_Logger::writeLog(DG_LogLevel::Error, 'Attempted to save invalid options.' . PHP_EOL . preg_replace('/\\s+/', ' ', print_r($new, true)), true, true);
     }
     return $ret;
 }