File "shortpixel-png2jpg.php"
Full path: /home/kosmetik/public_html/wp-content/plugins/shortpixel-image-optimiser/class/shortpixel-png2jpg.php
File
size: 22.45 B
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor Back
<?php
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Model\FileModel as FileModel;
use ShortPixel\Model\Directorymodel as DirectoryModel;
class ShortPixelPng2Jpg
{
private $_settings = null;
public function __construct($settings)
{
if (function_exists('wp_raise_memory_limit')) {
wp_raise_memory_limit('image');
}
$this->_settings = $settings;
}
protected function canConvertPng2Jpg($image)
{
$transparent = 0;
$transparent_pixel = $img = $bg = false;
if (!file_exists($image)) {
Log::addDebug("PNG2JPG FILE MISSING: " . $image);
$transparent = 1;
} elseif (ord(file_get_contents($image, false, null, 25, 1)) & 4) {
Log::addDebug("PNG2JPG: 25th byte has thrid bit 1 - transparency");
$transparent = 1;
} else {
$contents = file_get_contents($image);
if (stripos($contents, 'PLTE') !== false && stripos($contents, 'tRNS') !== false) {
$transparent = 1;
}
if (!$transparent) {
$is = getimagesize($image);
Log::addDebug("PNG2JPG Image width: " . $is[0] . " height: " . $is[1] . " aprox. size: " . round($is[0] * $is[1] * 5 / 1024 / 1024) . "M memory limit: " . ini_get('memory_limit') . " USED: " . memory_get_usage());
Log::addDebug("PNG2JPG create from png {$image}");
$img = @imagecreatefrompng($image);
Log::addDebug("PNG2JPG created from png");
if (!$img) {
Log::addDebug("PNG2JPG not a PNG, imagecreatefrompng failed ");
$transparent = true;
} else {
Log::addDebug("PNG2JPG is PNG");
$w = imagesx($img);
$h = imagesy($img);
Log::addDebug("PNG2JPG width {$w} height {$h}. Now checking pixels.");
for ($i = 0; $i < $w; $i++) {
for ($j = 0; $j < $h; $j++) {
$rgba = imagecolorat($img, $i, $j);
if (($rgba & 0x7f000000) >> 24) {
$transparent_pixel = true;
break;
}
}
}
}
}
}
Log::addDebug("PNG2JPG is " . (!$transparent && !$transparent_pixel ? " not" : "") . " transparent");
return array('notTransparent' => !$transparent && !$transparent_pixel, 'img' => $img);
}
protected function doConvertPng2Jpg($params, $backup, $suffixRegex = false, $img = false)
{
$image = $params['file'];
$fs = \wpSPIO()->filesystem();
Log::addDebug("PNG2JPG doConvert {$image}");
if (!$img) {
Log::addDebug("PNG2JPG doConvert create from PNG");
$img = file_exists($image) ? imagecreatefrompng($image) : false;
if (!$img) {
Log::addDebug("PNG2JPG doConvert image cannot be created.");
return (object) array("params" => $params, "unlink" => false);
}
}
$x = imagesx($img);
$y = imagesy($img);
Log::addDebug("PNG2JPG doConvert width {$x} height {$y}");
$bg = imagecreatetruecolor($x, $y);
if (!$bg) {
return (object) array("params" => $params, "unlink" => false);
}
imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
imagealphablending($bg, 1);
imagecopy($bg, $img, 0, 0, 0, 0, $x, $y);
imagedestroy($img);
$fsFile = $fs->getFile($image);
$filename = $fsFile->getFileName();
$newFileName = $fsFile->getFileBase() . '.jpg';
$fsNewFile = $fs->getFile($fsFile->getFileDir() . $newFileName);
$uniquefile = $this->unique_file($fsFile->getFileDir(), $fsNewFile);
$newPath = $uniquefile->getFullPath();
$newUrl = str_replace($filename, $uniquefile->getFileName(), $params['url']);
if (imagejpeg($bg, $newPath, 90)) {
Log::addDebug("PNG2JPG doConvert created JPEG at {$newPath}");
$newSize = filesize($newPath);
$origSize = filesize($image);
if ($newSize > $origSize * 0.95 || $newSize == 0) {
Log::addDebug("PNG2JPG converted image is larger ({$newSize} vs. {$origSize}), keeping the PNG");
unlink($newPath);
return (object) array("params" => $params, "unlink" => false);
}
if ($backup) {
$imageForBk = trailingslashit(dirname($image)) . ShortPixelAPI::MB_basename($newPath, '.jpg') . '.png';
Log::addDebug("imageForBk should be PNG: {$imageForBk}");
if ($image != $imageForBk) {
Log::addDebug("PNG2JPG doConvert rename {$image} to {$imageForBk}");
@rename($image, $imageForBk);
}
if (!file_exists($imageForBk)) {
unlink($newPath);
return (object) array("params" => $params, "unlink" => false);
}
$image = $imageForBk;
$ret = ShortPixelAPI::backupImage($image, array($image));
if ($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
Log::addDebug("PNG2JPG couldn't backup, keeping the PNG");
unlink($newPath);
return (object) array("params" => $params, "unlink" => false);
}
}
$params['file'] = $newPath;
Log::addDebug("Original_file should be PNG: {$image}");
$params['original_file'] = $image;
$params['url'] = $newUrl;
$params['type'] = 'image/jpeg';
$params['png_size'] = $origSize;
$params['jpg_size'] = $newSize;
}
return (object) array("params" => $params, "unlink" => $image);
}
private function unique_file(DirectoryModel $dir, FileModel $file, $number = 0)
{
if (!$file->exists()) {
return $file;
}
$number = 0;
$fs = \wpSPIO()->filesystem();
$base = $file->getFileBase();
$ext = $file->getExtension();
while ($file->exists()) {
$number++;
$numberbase = $base . '-' . $number;
Log::addDebug('check for unique file -- ' . $dir->getPath() . $numberbase . '.' . $ext);
$file = $fs->getFile($dir->getPath() . $numberbase . '.' . $ext);
}
return $file;
}
protected function isExcluded($params)
{
if (is_array($this->_settings->excludePatterns)) {
foreach ($this->_settings->excludePatterns as $item) {
$type = trim($item["type"]);
if (in_array($type, array('name', 'path')) && WpShortPixel::matchExcludePattern($params['file'], $item['value'])) {
return true;
}
if (isset($params['width']) && isset($params['height']) && 'size' == $type && WPShortPixel::isProcessableSize($params['width'], $params['height'], $item['value'])) {
return true;
}
}
}
return false;
}
public function convertPng2Jpg($params)
{
if (!$this->_settings->png2jpg || strtolower(substr($params['file'], -4)) !== '.png') {
return $params;
}
if ($this->isExcluded($params)) {
return $params;
}
$image = $params['file'];
Log::addDebug("Convert Media PNG to JPG on upload: {$image}");
if ($this->_settings->png2jpg == 2) {
$doConvert = true;
} else {
$ret = $this->canConvertPng2Jpg($image);
$doConvert = $ret['notTransparent'];
}
if ($doConvert) {
$ret = $this->doConvertPng2Jpg($params, $this->_settings->backupImages, false, isset($ret['img']) ? $ret['img'] : false);
if ($ret->unlink) {
@unlink($ret->unlink);
}
$paramsC = $ret->params;
if ($paramsC['type'] == 'image/jpeg') {
$conv = $this->_settings->convertedPng2Jpg;
foreach ($conv as $key => $val) {
if (time() - $val['timestamp'] > 3600) {
unset($conv[$key]);
}
}
$conv[$paramsC['file']] = array('pngFile' => $paramsC['original_file'], 'backup' => $this->_settings->backupImages, 'optimizationPercent' => round(100.0 * (1.0 - $paramsC['jpg_size'] / $paramsC['png_size'])), 'timestamp' => time());
$this->_settings->convertedPng2Jpg = $conv;
}
return $paramsC;
}
return $params;
}
public function checkConvertMediaPng2Jpg($itemHandler)
{
$meta = $itemHandler->getRawMeta();
$ID = $itemHandler->getId();
$fs = \wpSPIO()->filesystem();
if (!$this->_settings->png2jpg || !isset($meta['file']) || strtolower(substr($meta['file'], -4)) !== '.png') {
return;
}
if ($this->isExcluded($meta)) {
return;
}
Log::addDebug("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
$image = $meta['file'];
$imageFile = $fs->getAttachedFile($ID);
$imagePath = $imageFile->getFullPath();
$basePath = trailingslashit(str_replace($image, "", $imagePath));
$imageUrl = wp_get_attachment_url($ID);
$baseUrl = self::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl)));
if (isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > 3 && isset($meta['ShortPixel']['ErrCode']) && $meta['ShortPixel']['ErrCode'] == ShortPixelAPI::ERR_PNG2JPG_MEMORY) {
Log::addWarn("PNG2JPG too many memory failures!");
throw new Exception('Not enough memory to convert from PNG to JPG.', ShortPixelAPI::ERR_PNG2JPG_MEMORY);
}
$meta['ShortPixelImprovement'] = 'Error: <i>Not enough memory to convert from PNG to JPG.</i>';
if (!isset($meta['ShortPixel']) || !is_array($meta['ShortPixel'])) {
$meta['ShortPixel'] = array();
}
$meta['ShortPixel']['Retries'] = isset($meta['ShortPixel']['Retries']) ? $meta['ShortPixel']['Retries'] + 1 : 1;
$meta['ShortPixel']['ErrCode'] = ShortPixelAPI::ERR_PNG2JPG_MEMORY;
update_post_meta($ID, '_wp_attachment_metadata', $meta);
if ($this->_settings->png2jpg == 2) {
$doConvert = true;
} else {
$retC = $this->canConvertPng2Jpg($imagePath);
$doConvert = $retC['notTransparent'];
}
if (!$doConvert) {
Log::addDebug("PNG2JPG not a PNG, or transparent when this setting is off - " . $imagePath);
return $meta;
}
Log::addDebug(" CONVERTING MAIN: {$imagePath}");
$retMain = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, isset($retC['img']) ? $retC['img'] : false);
Log::addDebug("PNG2JPG doConvert Main RETURNED " . json_encode($retMain));
$ret = $retMain->params;
$toUnlink = array();
$toReplace = array();
unset($meta['ShortPixelImprovement']);
unset($meta['ShortPixel']['ErrCode']);
$meta['ShortPixel']['Retries'] -= 1;
update_post_meta($ID, '_wp_attachment_metadata', $meta);
if ($ret['type'] == 'image/jpeg') {
$toUnlink[] = $retMain->unlink;
do_action('shortpixel/image/convertpng2jpg_before', $ID, $meta);
$baseRelPath = dirname($image);
if ($baseRelPath == '.') {
$baseRelPath = '';
} else {
$baseRelPath = trailingslashit($baseRelPath);
}
$toReplace[self::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($ret['file']);
$pngSize = $ret['png_size'];
$jpgSize = $ret['jpg_size'];
Log::addDebug(" IMAGE PATH: {$imagePath}");
$imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
Log::addDebug(" SET IMAGE PATH: {$imagePath}");
$duplicates = $this->updateFileAlsoInWPMLDuplicates($ID, $meta, str_replace($basePath, '', $ret['file']));
Log::addDebug(" WPML duplicates: " . json_encode($duplicates));
$originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
$filesConverted = array();
foreach ($meta['sizes'] as $size => $info) {
if (isset($filesConverted[$info['file']])) {
Log::addDebug("PNG2JPG DUPLICATED THUMB: " . $size);
if ($filesConverted[$info['file']] === false) {
Log::addDebug("PNG2JPG DUPLICATED THUMB not converted");
continue;
}
Log::addDebug("PNG2JPG DUPLICATED THUMB already converted");
$rett = $filesConverted[$info['file']];
} else {
$retThumb = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, "[0-9]+x[0-9]+");
$rett = $retThumb->params;
}
Log::addDebug("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
if ($rett['type'] == 'image/jpeg') {
$toUnlink[] = $retThumb->unlink;
Log::addDebug("PNG2JPG thumb is jpg");
$pngSize += $rett['png_size'];
$jpgSize += $rett['jpg_size'];
Log::addDebug("PNG2JPG total PNG size: {$pngSize} total JPG size: {$jpgSize}");
$originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
Log::addDebug("PNG2JPG thumb original: " . $originalSizes[$size]['file']);
$toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
$filesConverted[$info['file']] = $rett;
$this->updateThumbAlsoInWPMLDuplicates($ID, $meta, $duplicates, $size, wp_basename($rett['file']));
} else {
$filesConverted[$info['file']] = false;
}
}
$meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes, 'backup' => $this->_settings->backupImages, 'optimizationPercent' => round(100.0 * (1.0 - $jpgSize / $pngSize)));
update_post_meta($ID, '_wp_attachment_metadata', $meta);
$itemHandler->deleteItemCache();
Log::addDebug("Updated meta: " . json_encode($meta));
wp_update_post(array('ID' => $ID, 'post_mime_type' => 'image/jpeg'));
do_action('shortpixel/image/convertpng2jpg_after', $ID, $meta);
}
if (count($toReplace)) {
self::png2JpgUpdateUrls(array(), $toReplace);
}
$fs = \wpSPIO()->filesystem();
foreach ($toUnlink as $unlink) {
if ($unlink) {
Log::addDebug("PNG2JPG remove file {$unlink}");
$fileObj = $fs->getFile($unlink);
$fileObj->delete();
}
}
Log::addDebug("PNG2JPG done. Return: " . json_encode($meta));
return $meta;
}
protected function updateFileAlsoInWPMLDuplicates($parentID, &$parentMeta, $file)
{
$duplicates = ShortPixelMetaFacade::getWPMLDuplicates($parentID);
foreach ($duplicates as $ID) {
$meta = $parentID == $ID ? $parentMeta : wp_get_attachment_metadata($ID);
$meta['file'] = $file;
$meta['type'] = 'image/jpeg';
if ($parentID == $ID) {
$parentMeta = $meta;
}
update_attached_file($ID, $meta['file']);
update_post_meta($ID, '_wp_attachment_metadata', $meta);
}
return $duplicates;
}
protected function updateThumbAlsoInWPMLDuplicates($parentID, &$parentMeta, $duplicates, $size, $thumbnail)
{
foreach ($duplicates as $ID) {
$meta = $parentID == $ID ? $parentMeta : wp_get_attachment_metadata($ID);
$meta['sizes'][$size]['file'] = wp_basename($thumbnail);
$meta['sizes'][$size]['mime-type'] = 'image/jpeg';
if ($parentID == $ID) {
$parentMeta = $meta;
}
update_post_meta($ID, '_wp_attachment_metadata', $meta);
}
}
public static function png2JpgUpdateUrls($options, $map)
{
global $wpdb;
Log::addDebug("PNG2JPG update URLS " . json_encode($map));
$results = array();
$queries = array('content' => array("UPDATE {$wpdb->posts} SET post_content = replace(post_content, %s, %s)", __('Content Items (Posts, Pages, Custom Post Types, Revisions)', 'shortpixel-image-optimiser')), 'excerpts' => array("UPDATE {$wpdb->posts} SET post_excerpt = replace(post_excerpt, %s, %s)", __('Excerpts', 'shortpixel-image-optimiser')), 'attachments' => array("UPDATE {$wpdb->posts} SET guid = replace(guid, %s, %s) WHERE post_type = 'attachment'", __('Attachments', 'shortpixel-image-optimiser')), 'links' => array("UPDATE {$wpdb->links} SET link_url = replace(link_url, %s, %s)", __('Links', 'shortpixel-image-optimiser')), 'custom' => array("UPDATE {$wpdb->postmeta} SET meta_value = replace(meta_value, %s, %s)", __('Custom Fields', 'shortpixel-image-optimiser')), 'guids' => array("UPDATE {$wpdb->posts} SET guid = replace(guid, %s, %s) ", __('GUIDs', 'shortpixel-image-optimiser')));
if (count($options) == 0) {
$options = array_keys($queries);
}
$startTime = microtime(true);
foreach ($options as $option) {
if ($option == 'custom') {
$n = 0;
$page_size = WpShortPixelMediaLbraryAdapter::getOptimalChunkSize('postmeta');
for ($page = 0; $items = $wpdb->get_results("SELECT * FROM {$wpdb->postmeta} LIMIT " . $page * $page_size . ", {$page_size}"); $page++) {
foreach ($items as $item) {
$value = $item->meta_value;
if (trim($value) == '' || $item->meta_key == '_wp_attached_file' || $item->meta_key == '_wp_attachment_metadata') {
continue;
}
$edited = (object) array('data' => $value, 'replaced' => false);
foreach ($map as $oldurl => $newurl) {
if (strlen($newurl)) {
$editedOne = self::png2JpgUnserializeReplace($oldurl, $newurl, $edited->data);
$edited->data = $editedOne->data;
$edited->replaced = $edited->replaced || $editedOne->replaced;
}
}
if ($edited->replaced) {
$fix = $wpdb->query("UPDATE {$wpdb->postmeta} SET meta_value = '" . $edited->data . "' WHERE meta_id = " . $item->meta_id);
if ($fix) {
$n++;
}
}
}
$timeElapsed = microtime(true) - $startTime;
if ($timeElapsed > SHORTPIXEL_MAX_EXECUTION_TIME / 2) {
if (\wpSPIO()->env()->is_function_usable('set_time_limit') && set_time_limit(SHORTPIXEL_MAX_EXECUTION_TIME)) {
$startTime += SHORTPIXEL_MAX_EXECUTION_TIME / 2;
} else {
break;
}
}
}
$results[$option] = array($n, $queries[$option][1]);
} else {
foreach ($map as $oldurl => $newurl) {
if (strlen($newurl)) {
$prepared = $wpdb->prepare($queries[$option][0], $oldurl, $newurl);
Log::addDebug("Prepared Query", $prepared);
$result = $wpdb->query($prepared);
$results[$option] = array($result, $queries[$option][1]);
}
}
}
}
return $results;
}
public static function removeUrlProtocol($url)
{
return preg_replace("/^http[s]{0,1}:\\/\\//", "", $url);
}
public static function png2JpgUnserializeReplace($from = '', $to = '', $data = '', $serialised = false)
{
$replaced = false;
try {
if (false !== is_serialized($data)) {
if (false === strpos($data, wp_basename($from))) {
return (object) array('data' => $data, 'replaced' => false);
}
$unserialized = unserialize($data);
$ret = self::png2JpgUnserializeReplace($from, $to, $unserialized, true);
$data = $ret->data;
$replaced = $replaced || $ret->replaced;
} elseif (is_array($data)) {
$_tmp = array();
foreach ($data as $key => $value) {
$ret = self::png2JpgUnserializeReplace($from, $to, $value, false);
$_tmp[$key] = $ret->data;
$replaced = $replaced || $ret->replaced;
}
$data = $_tmp;
unset($_tmp);
} elseif (is_object($data)) {
foreach (get_object_vars($data) as $key => $value) {
$ret = self::png2JpgUnserializeReplace($from, $to, $value, false);
$_tmp[$key] = $ret->data;
$replaced = $replaced || $ret->replaced;
}
$data = (object) $_tmp;
} elseif (is_string($data)) {
if (false !== strpos($data, $from)) {
$replaced = true;
$data = str_replace($from, $to, $data);
} elseif (strlen($from) > strlen($data) && strlen($data) >= strlen(wp_basename($from)) && strpos($from, $data) == strlen($from) - strlen($data)) {
$replaced = true;
$data = substr($to, strlen($from) - strlen($data));
}
}
if ($serialised) {
return (object) array('data' => serialize($data), 'replaced' => $replaced);
}
} catch (Exception $error) {
}
return (object) array('data' => $data, 'replaced' => $replaced);
}
}