1<?php 2namespace Amenadiel\JpGraph\Image; 3 4use Amenadiel\JpGraph\Util; 5 6//======================================================================= 7// CLASS ImgStreamCache 8// Description: Handle caching of graphs to files. All image output goes 9// through this class 10//======================================================================= 11class ImgStreamCache 12{ 13 private $cache_dir; 14 private $timeout = 0; // Infinite timeout 15 //--------------- 16 // CONSTRUCTOR 17 public function __construct($aCacheDir = CACHE_DIR) 18 { 19 $this->cache_dir = $aCacheDir; 20 } 21 22 //--------------- 23 // PUBLIC METHODS 24 25 // Specify a timeout (in minutes) for the file. If the file is older then the 26 // timeout value it will be overwritten with a newer version. 27 // If timeout is set to 0 this is the same as infinite large timeout and if 28 // timeout is set to -1 this is the same as infinite small timeout 29 public function SetTimeout($aTimeout) 30 { 31 $this->timeout = $aTimeout; 32 } 33 34 // Output image to browser and also write it to the cache 35 public function PutAndStream($aImage, $aCacheFileName, $aInline, $aStrokeFileName) 36 { 37 38 // Check if we should always stroke the image to a file 39 if (_FORCE_IMGTOFILE) { 40 $aStrokeFileName = _FORCE_IMGDIR . GenImgName(); 41 } 42 43 if ($aStrokeFileName != '') { 44 if ($aStrokeFileName == 'auto') { 45 $aStrokeFileName = GenImgName(); 46 } 47 48 if (file_exists($aStrokeFileName)) { 49 50 // Wait for lock (to make sure no readers are trying to access the image) 51 $fd = fopen($aStrokeFileName, 'w'); 52 $lock = flock($fd, LOCK_EX); 53 54 // Since the image write routines only accepts a filename which must not 55 // exist we need to delete the old file first 56 if (!@unlink($aStrokeFileName)) { 57 $lock = flock($fd, LOCK_UN); 58 Util\JpGraphError::RaiseL(25111, $aStrokeFileName); 59 //(" Can't delete cached image $aStrokeFileName. Permission problem?"); 60 } 61 $aImage->Stream($aStrokeFileName); 62 $lock = flock($fd, LOCK_UN); 63 fclose($fd); 64 } else { 65 $aImage->Stream($aStrokeFileName); 66 } 67 68 return; 69 } 70 71 if ($aCacheFileName != '' && USE_CACHE) { 72 $aCacheFileName = $this->cache_dir . $aCacheFileName; 73 if (file_exists($aCacheFileName)) { 74 if (!$aInline) { 75 // If we are generating image off-line (just writing to the cache) 76 // and the file exists and is still valid (no timeout) 77 // then do nothing, just return. 78 $diff = time() - filemtime($aCacheFileName); 79 if ($diff < 0) { 80 Util\JpGraphError::RaiseL(25112, $aCacheFileName); 81 //(" Cached imagefile ($aCacheFileName) has file date in the future!!"); 82 } 83 if ($this->timeout > 0 && ($diff <= $this->timeout * 60)) { 84 return; 85 } 86 } 87 88 // Wait for lock (to make sure no readers are trying to access the image) 89 $fd = fopen($aCacheFileName, 'w'); 90 $lock = flock($fd, LOCK_EX); 91 92 if (!@unlink($aCacheFileName)) { 93 $lock = flock($fd, LOCK_UN); 94 Util\JpGraphError::RaiseL(25113, $aStrokeFileName); 95 //(" Can't delete cached image $aStrokeFileName. Permission problem?"); 96 } 97 $aImage->Stream($aCacheFileName); 98 $lock = flock($fd, LOCK_UN); 99 fclose($fd); 100 } else { 101 $this->MakeDirs(dirname($aCacheFileName)); 102 if (!is_writeable(dirname($aCacheFileName))) { 103 Util\JpGraphError::RaiseL(25114, $aCacheFileName); 104 //('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); 105 } 106 $aImage->Stream($aCacheFileName); 107 } 108 109 $res = true; 110 // Set group to specified 111 if (CACHE_FILE_GROUP != '') { 112 $res = @chgrp($aCacheFileName, CACHE_FILE_GROUP); 113 } 114 if (CACHE_FILE_MOD != '') { 115 $res = @chmod($aCacheFileName, CACHE_FILE_MOD); 116 } 117 if (!$res) { 118 Util\JpGraphError::RaiseL(25115, $aStrokeFileName); 119 //(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); 120 } 121 122 $aImage->Destroy(); 123 if ($aInline) { 124 if ($fh = @fopen($aCacheFileName, "rb")) { 125 $aImage->Headers(); 126 fpassthru($fh); 127 return; 128 } else { 129 Util\JpGraphError::RaiseL(25116, $aFile); //(" Cant open file from cache [$aFile]"); 130 } 131 } 132 } elseif ($aInline) { 133 $aImage->Headers(); 134 $aImage->Stream(); 135 return; 136 } 137 } 138 139 public function IsValid($aCacheFileName) 140 { 141 $aCacheFileName = $this->cache_dir . $aCacheFileName; 142 if (USE_CACHE && file_exists($aCacheFileName)) { 143 $diff = time() - filemtime($aCacheFileName); 144 if ($this->timeout > 0 && ($diff > $this->timeout * 60)) { 145 return false; 146 } else { 147 return true; 148 } 149 } else { 150 return false; 151 } 152 } 153 154 public function StreamImgFile($aImage, $aCacheFileName) 155 { 156 $aCacheFileName = $this->cache_dir . $aCacheFileName; 157 if ($fh = @fopen($aCacheFileName, 'rb')) { 158 $lock = flock($fh, LOCK_SH); 159 $aImage->Headers(); 160 fpassthru($fh); 161 $lock = flock($fh, LOCK_UN); 162 fclose($fh); 163 return true; 164 } else { 165 Util\JpGraphError::RaiseL(25117, $aCacheFileName); //(" Can't open cached image \"$aCacheFileName\" for reading."); 166 } 167 } 168 169 // Check if a given image is in cache and in that case 170 // pass it directly on to web browser. Return false if the 171 // image file doesn't exist or exists but is to old 172 public function GetAndStream($aImage, $aCacheFileName) 173 { 174 if ($this->Isvalid($aCacheFileName)) { 175 $this->StreamImgFile($aImage, $aCacheFileName); 176 } else { 177 return false; 178 } 179 } 180 181 //--------------- 182 // PRIVATE METHODS 183 // Create all necessary directories in a path 184 public function MakeDirs($aFile) 185 { 186 $dirs = array(); 187 // In order to better work when open_basedir is enabled 188 // we do not create directories in the root path 189 while ($aFile != '/' && !(file_exists($aFile))) { 190 $dirs[] = $aFile . '/'; 191 $aFile = dirname($aFile); 192 } 193 for ($i = sizeof($dirs) - 1; $i >= 0; $i--) { 194 if (!@mkdir($dirs[$i], 0777)) { 195 Util\JpGraphError::RaiseL(25118, $aFile); //(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); 196 } 197 // We also specify mode here after we have changed group. 198 // This is necessary if Apache user doesn't belong the 199 // default group and hence can't specify group permission 200 // in the previous mkdir() call 201 if (CACHE_FILE_GROUP != "") { 202 $res = true; 203 $res = @chgrp($dirs[$i], CACHE_FILE_GROUP); 204 $res = @chmod($dirs[$i], 0777); 205 if (!$res) { 206 Util\JpGraphError::RaiseL(25119, $aFile); //(" Can't set permissions for $aFile. Permission problems?"); 207 } 208 } 209 } 210 return true; 211 } 212} // CLASS Cache 213