oxdynimggenerator.php

Go to the documentation of this file.
00001 <?php
00002 
00003 require_once dirname(__FILE__) . "/../bootstrap.php";
00004 
00005 // Checks if base path getter does not exist
00006 if (!function_exists("getShopBasePath")) {
00012     function getShopBasePath()
00013     {
00014         return realpath(dirname(__FILE__) . '/..') . '/';
00015     }
00016 }
00017 
00018 
00019 // disables admin
00020 if (!function_exists('isAdmin')) {
00026     function isAdmin()
00027     {
00028         return false;
00029     }
00030 }
00031 
00032 // starts shop framework and returns config instance
00033 if (!function_exists("getConfig")) {
00039     function getConfig()
00040     {
00041         // custom functions file
00042         include_once getShopBasePath() . 'modules/functions.php';
00043 
00044         // Generic utility method file
00045         include_once getShopBasePath() . 'core/oxfunctions.php';
00046 
00047         // initializes singleton config class
00048         return oxRegistry::getConfig();
00049     }
00050 }
00051 
00052 // Checks if instance name getter does not exist
00053 if (!function_exists("getGeneratorInstanceName")) {
00059     function getGeneratorInstanceName()
00060     {
00061         return "oxdynimggenerator";
00062     }
00063 }
00064 
00065 // checks if GD library version getter does not exist
00066 if (!function_exists("getGdVersion")) {
00072     function getGdVersion()
00073     {
00074         static $iVersion = null;
00075 
00076         if ($iVersion === null) {
00077             $iVersion = false;
00078             if (function_exists("gd_info")) {
00079                 // extracting GD version from php
00080                 $aInfo = gd_info();
00081                 if (isset($aInfo["GD Version"])) {
00082                     $iVersion = version_compare(preg_replace("/[^0-9\.]/", "", $aInfo["GD Version"]), 1, '>') ? 2 : 1;
00083                 }
00084             }
00085 
00086         }
00087 
00088         return $iVersion;
00089     }
00090 }
00091 
00092 // checks if image utils file loader does not exist
00093 if (!function_exists("includeImageUtils")) {
00097     function includeImageUtils()
00098     {
00099         include_once getShopBasePath() . "core/utils/oxpicgenerator.php";
00100     }
00101 }
00102 
00106 class oxDynImgGenerator
00107 {
00108 
00114     protected static $_oInstance = null;
00115 
00121     protected $_aHeaders = array();
00122 
00128     protected $_aAllowedImgTypes = array("jpg", "jpeg", "png", "gif");
00129 
00136     protected $_sImageInfoSep = "_";
00137 
00143     protected $_hLockHandle = null;
00144 
00150     protected $_sImageUri = null;
00151 
00157     protected $_aConfParamToPath = array( // ** product
00158         "sIconsize"             => '/.*\/generated\/product\/(icon|\d+)\/\d+\_\d+\_\d+$/', // Icon size
00159         "sThumbnailsize"        => '/.*\/generated\/product\/(thumb|\d+)\/\d+\_\d+\_\d+$/', // Thumbnail size
00160         "sZoomImageSize"        => '/.*\/generated\/product\/\d+\/\d+\_\d+\_\d+$/', // Zoom picture size
00161         "aDetailImageSizes"     => '/.*\/generated\/product\/\d+\/\d+\_\d+\_\d+$/', // Product picture size
00162 
00163         // ** manufacturer/vendor
00164         "sManufacturerIconsize" => '/.*\/generated\/(manufacturer|vendor)\/icon\/\d+\_\d+\_\d+$/', // Manufacturer's|brand logo size
00165 
00166         // ** category
00167         "sCatThumbnailsize"     => '/.*\/generated\/category\/thumb\/\d+\_\d+\_\d+$/', // Category picture size
00168         "sCatIconsize"          => '/.*\/generated\/category\/icon\/\d+\_\d+\_\d+$/', // Size of a subcategory's picture
00169         "sCatPromotionsize"     => '/.*\/generated\/category\/promo_icon\/\d+\_\d+\_\d+$/' // Category picture size for promotion on startpage
00170     );
00171 
00177     public static function getInstance()
00178     {
00179         if (self::$_oInstance === null) {
00180             $sInstanceName = getGeneratorInstanceName();
00181             self::$_oInstance = new $sInstanceName();
00182         }
00183 
00184         return self::$_oInstance;
00185     }
00186 
00198     public function __call($sMethod, $aArgs)
00199     {
00200         if (defined('OXID_PHP_UNIT')) {
00201             if (substr($sMethod, 0, 4) == "UNIT") {
00202                 $sMethod = str_replace("UNIT", "_", $sMethod);
00203             }
00204             if (method_exists($this, $sMethod)) {
00205                 return call_user_func_array(array(& $this, $sMethod), $aArgs);
00206             }
00207         }
00208 
00209         throw new oxSystemComponentException("Function '$sMethod' does not exist or is not accessible! (" . get_class($this) . ")" . PHP_EOL);
00210     }
00211 
00217     protected function _getShopBasePath()
00218     {
00219         return getConfig()->getConfigParam("sShopDir");
00220     }
00221 
00227     protected function _getImageUri()
00228     {
00229         if ($this->_sImageUri === null) {
00230 
00231             $this->_sImageUri = "";
00232             $sReqPath = "out/pictures/generated";
00233 
00234 
00235             $sReqImg = isset($_SERVER["REQUEST_URI"]) ? urldecode($_SERVER["REQUEST_URI"]) : "";
00236             if (($iPos = strpos($sReqImg, $sReqPath)) !== false) {
00237                 $this->_sImageUri = substr($sReqImg, $iPos);
00238             }
00239 
00240             $this->_sImageUri = trim($this->_sImageUri, "/");
00241         }
00242 
00243         return $this->_sImageUri;
00244     }
00245 
00251     protected function _getImageName()
00252     {
00253         return basename($this->_getImageUri());
00254     }
00255 
00261     protected function _getImageMasterPath()
00262     {
00263         $sUri = $this->_getImageUri();
00264         $sPath = false;
00265 
00266         if ($sUri && ($sPath = dirname(dirname($sUri)))) {
00267             $sPath = preg_replace("/\/([^\/]*)\/([^\/]*)\/([^\/]*)$/", "/master/\\2/\\3/", $sPath);
00268         }
00269 
00270         return $sPath;
00271     }
00272 
00278     protected function _getImageInfo()
00279     {
00280         $aInfo = array();
00281         if (($sUri = $this->_getImageUri())) {
00282             $aInfo = explode($this->_sImageInfoSep, basename(dirname($sUri)));
00283         }
00284 
00285         return $aInfo;
00286     }
00287 
00293     protected function _getImageTarget()
00294     {
00295         return $this->_getShopBasePath() . $this->_getImageUri();
00296     }
00297 
00303     protected function _getNopicImageTarget()
00304     {
00305         $sPath = $this->_getShopBasePath() . $this->_getImageUri();
00306 
00307         return str_replace($this->_getImageName(), "nopic.jpg", $sPath);
00308     }
00309 
00315     protected function _getImageType()
00316     {
00317         $sType = preg_replace("/.*\.(png|jp(e)?g|gif)$/", "\\1", $this->_getImageName());
00318         $sType = (strcmp($sType, "jpg") == 0) ? "jpeg" : $sType;
00319 
00320         return in_array($sType, $this->_aAllowedImgTypes) ? $sType : false;
00321     }
00322 
00333     protected function _generatePng($sSource, $sTarget, $iWidth, $iHeight)
00334     {
00335         return resizePng($sSource, $sTarget, $iWidth, $iHeight, @getimagesize($sSource), getGdVersion(), null);
00336     }
00337 
00349     protected function _generateJpg($sSource, $sTarget, $iWidth, $iHeight, $iQuality)
00350     {
00351         return resizeJpeg($sSource, $sTarget, $iWidth, $iHeight, @getimagesize($sSource), getGdVersion(), null, $iQuality);
00352     }
00353 
00364     protected function _generateGif($sSource, $sTarget, $iWidth, $iHeight)
00365     {
00366         $aImageInfo = @getimagesize($sSource);
00367 
00368         return resizeGif($sSource, $sTarget, $iWidth, $iHeight, $aImageInfo[0], $aImageInfo[1], getGdVersion());
00369     }
00370 
00379     protected function _isTargetPathValid($sPath)
00380     {
00381         $blValid = true;
00382         $sDir = dirname(trim($sPath));
00383 
00384         // first time folder access?
00385         if (!is_dir($sDir) && ($blValid = $this->_isValidPath($sDir))) {
00386             // creating missing folders
00387             $blValid = $this->_createFolders($sDir);
00388         }
00389 
00390         return $blValid;
00391     }
00392 
00400     protected function _createFolders($sDir)
00401     {
00402         $oConfig = getConfig();
00403         $sPicFolderPath = dirname($oConfig->getMasterPictureDir());
00404 
00405         $blDone = false;
00406         if ($sPicFolderPath && is_dir($sPicFolderPath)) {
00407 
00408             // if its in main path..
00409             if (strcmp($sPicFolderPath, substr($sDir, 0, strlen($sPicFolderPath))) == 0) {
00410                 // folder does not exist yet?
00411                 if (!($blDone = file_exists($sDir))) {
00412                     clearstatcache();
00413                     // in case creation did not succeed, maybe another process allready created folder?
00414                     $iMode = 0755;
00415                     if (defined('OXID_PHP_UNIT')) {
00416                         $iMode = 0777;
00417                     }
00418                     $blDone = mkdir($sDir, $iMode, true) || file_exists($sDir);
00419                 }
00420             }
00421         }
00422 
00423         return $blDone;
00424     }
00425 
00433     protected function _isValidPath($sPath)
00434     {
00435         $blValid = false;
00436 
00437         list($iWidth, $iHeight, $sQuality) = $this->_getImageInfo();
00438         if ($iWidth && $iHeight && $sQuality) {
00439 
00440             $oConfig = getConfig();
00441             $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
00442 
00443             // parameter names
00444             $sNames = '';
00445             foreach ($this->_aConfParamToPath as $sParamName => $sPathReg) {
00446                 if (preg_match($sPathReg, $sPath)) {
00447                     if ($sNames) {
00448                         $sNames .= ", ";
00449                     }
00450                     $sNames .= $oDb->quote($sParamName);
00451 
00452                     if ($sParamName == "sManufacturerIconsize" || $sParamName == "sCatIconsize") {
00453                         $sNames .= ", " . $oDb->quote("sIconsize");
00454                     }
00455                 }
00456             }
00457 
00458             // any name matching path?
00459             if ($sNames) {
00460 
00461                 $sDecodeField = $oConfig->getDecodeValueQuery();
00462 
00463                 // selecting shop which image quality matches user given
00464                 $sQ = "select oxshopid from oxconfig where oxvarname = 'sDefaultImageQuality' and
00465                        {$sDecodeField} = " . $oDb->quote($sQuality);
00466 
00467                 $aShopIds = $oDb->getAll($sQ);
00468 
00469                 // building query:
00470                 // shop id
00471                 $sShopIds = '';
00472                 foreach ($aShopIds as $aShopId) {
00473 
00474                     // probably here we can resolve and check shop id to shorten check?
00475 
00476 
00477                     if ($sShopIds) {
00478                         $sShopIds .= ", ";
00479                     }
00480                     $sShopIds .= $oDb->quote($aShopId["oxshopid"]);
00481                 }
00482 
00483                 // any shop matching quality
00484                 if ($sShopIds) {
00485 
00486                     //
00487                     $sCheckSize = "$iWidth*$iHeight";
00488 
00489                     // selecting config variables to check
00490                     $sQ = "select oxvartype, {$sDecodeField} as oxvarvalue from oxconfig
00491                            where oxvarname in ( {$sNames} ) and oxshopid in ( {$sShopIds} ) order by oxshopid";
00492 
00493                     $aValues = $oDb->getAll($sQ);
00494                     foreach ($aValues as $aValue) {
00495                         $aConfValues = (array) $oConfig->decodeValue($aValue["oxvartype"], $aValue["oxvarvalue"]);
00496                         foreach ($aConfValues as $sValue) {
00497                             if (strcmp($sCheckSize, $sValue) == 0) {
00498                                 $blValid = true;
00499                                 break;
00500                             }
00501                         }
00502                     }
00503                 }
00504             }
00505         }
00506 
00507         return $blValid;
00508     }
00509 
00518     protected function _generateImage($sImageSource, $sImageTarget)
00519     {
00520         $sPath = false;
00521 
00522         if (getGdVersion() !== false && $this->_isTargetPathValid($sImageTarget) && ($sImageType = $this->_getImageType())) {
00523 
00524             // including generator files
00525             includeImageUtils();
00526 
00527             // in case lock file creation failed should check if another process did not created image yet
00528             if ($this->_lock($sImageTarget)) {
00529 
00530                 // extracting image info - size/quality
00531                 list($iWidth, $iHeight, $iQuality) = $this->_getImageInfo();
00532                 switch ($sImageType) {
00533                     case "png":
00534                         $sPath = $this->_generatePng($sImageSource, $sImageTarget, $iWidth, $iHeight);
00535                         break;
00536                     case "jpeg":
00537                         $sPath = $this->_generateJpg($sImageSource, $sImageTarget, $iWidth, $iHeight, $iQuality);
00538                         break;
00539                     case "gif":
00540                         $sPath = $this->_generateGif($sImageSource, $sImageTarget, $iWidth, $iHeight);
00541                         break;
00542                 }
00543 
00544                 // releasing..
00545                 if ($sPath) {
00546                     $this->_unlock($sImageTarget);
00547                 }
00548             } else {
00549                 // assuming that image was created by another process
00550                 $sPath = file_exists($sImageTarget) ? $sImageTarget : false;
00551             }
00552         }
00553 
00554         return $sPath;
00555     }
00556 
00564     protected function _getLockName($sName)
00565     {
00566         return "$sName.lck";
00567     }
00568 
00576     protected function _lock($sSource)
00577     {
00578         $blLocked = false;
00579         $sLockName = $this->_getLockName($sSource);
00580 
00581         // creating lock file
00582         $this->_hLockHandle = @fopen($this->_getLockName($sSource), "w");
00583         if ($this->_hLockHandle) {
00584             if (!($blLocked = flock($this->_hLockHandle, LOCK_EX))) {
00585                 // on failure - closing
00586                 fclose($rHandle);
00587             }
00588         }
00589 
00590         // in case system does not support file lockings
00591         if (!$blLocked) {
00592             // start a blank file to inform other processes we are dealing with it.
00593             if (!(file_exists($this->_getLockName($sSource)) && abs(time() - filectime($this->_getLockName($sSource)) < 40))) {
00594                 if ($this->_hLockHandle = @fopen($this->_getLockName($sSource), "w")) {
00595                     $blLocked = true;
00596                 }
00597             }
00598         }
00599 
00600         return $blLocked;
00601     }
00602 
00608     protected function _unlock($sSource)
00609     {
00610         if ($this->_hLockHandle) {
00611             flock($this->_hLockHandle, LOCK_UN);
00612             fclose($this->_hLockHandle);
00613             unlink($this->_getLockName($sSource));
00614         }
00615     }
00616 
00625     public function getImagePath($sAbsPath = false)
00626     {
00627         if ($sAbsPath) {
00628             $this->_sImageUri = str_replace($this->_getShopBasePath(), "", $sAbsPath);
00629         }
00630 
00631         $sImagePath = false;
00632         $sMasterPath = $this->_getImageMasterPath();
00633 
00634         // building base path + extracting image name + extracting master image path
00635         $sMasterImagePath = $this->_getShopBasePath() . $sMasterPath . $this->_getImageName();
00636 
00637         if (file_exists($sMasterImagePath)) {
00638             $sGenImagePath = $this->_getImageTarget();
00639         } else {
00640             // nopic master path
00641             $sMasterImagePath = $this->_getShopBasePath() . dirname(dirname($sMasterPath)) . "/nopic.jpg";
00642             $sGenImagePath = $this->_getNopicImageTarget();
00643 
00644             // 404 header for nopic
00645             $this->_setHeader("HTTP/1.0 404 Not Found");
00646         }
00647 
00648         // checking if master image is accessible
00649         if (file_exists($sGenImagePath)) {
00650             $sImagePath = $sGenImagePath;
00651         } elseif (file_exists($sMasterImagePath)) {
00652             // generating image
00653             $sImagePath = $this->_generateImage($sMasterImagePath, $sGenImagePath);
00654         }
00655 
00656         if ($sImagePath) {
00657             // image type header
00658             $this->_setHeader("Content-Type: image/" . $this->_getImageType());
00659         } else {
00660             // unable to output any file
00661             $this->_setHeader("HTTP/1.0 404 Not Found");
00662         }
00663 
00664         return $sImagePath;
00665     }
00666 
00672     public function outputImage()
00673     {
00674         $blBuffer = true;
00675         if (defined('OXID_PHP_UNIT')) {
00676             $blBuffer = false;
00677         }
00678 
00679         // starting output buffering
00680         if ($blBuffer) {
00681             ob_start();
00682         }
00683 
00684         //
00685         $sImgPath = $this->getImagePath();
00686 
00687         // cleaning extra output
00688         if ($blBuffer) {
00689             ob_clean();
00690         }
00691 
00692         // outputting headers
00693         $aHeaders = $this->_getHeaders();
00694         foreach ($aHeaders as $sHeader) {
00695             header($sHeader);
00696         }
00697 
00698         // sending headers
00699         if ($blBuffer) {
00700             ob_end_flush();
00701         }
00702 
00703         // file is generated?
00704         if ($sImgPath) {
00705             // outputting file
00706             @readfile($sImgPath);
00707         }
00708     }
00709 
00715     protected function _setHeader($sHeader)
00716     {
00717         $this->_aHeaders[] = $sHeader;
00718     }
00719 
00725     protected function _getHeaders()
00726     {
00727         return $this->_aHeaders;
00728     }
00729 }