File indexing completed on 2025-01-26 05:29:15

0001 <?php
0002 
0003 namespace Intervention\Image;
0004 
0005 use GuzzleHttp\Psr7\Stream;
0006 use Psr\Http\Message\StreamInterface;
0007 
0008 abstract class AbstractDecoder
0009 {
0010     /**
0011      * Initiates new image from path in filesystem
0012      *
0013      * @param  string $path
0014      * @return \Intervention\Image\Image
0015      */
0016     abstract public function initFromPath($path);
0017 
0018     /**
0019      * Initiates new image from binary data
0020      *
0021      * @param  string $data
0022      * @return \Intervention\Image\Image
0023      */
0024     abstract public function initFromBinary($data);
0025 
0026     /**
0027      * Initiates new image from GD resource
0028      *
0029      * @param  Resource $resource
0030      * @return \Intervention\Image\Image
0031      */
0032     abstract public function initFromGdResource($resource);
0033 
0034     /**
0035      * Initiates new image from Imagick object
0036      *
0037      * @param \Imagick $object
0038      * @return \Intervention\Image\Image
0039      */
0040     abstract public function initFromImagick(\Imagick $object);
0041 
0042     /**
0043      * Buffer of input data
0044      *
0045      * @var mixed
0046      */
0047     private $data;
0048 
0049     /**
0050      * Creates new Decoder with data
0051      *
0052      * @param mixed $data
0053      */
0054     public function __construct($data = null)
0055     {
0056         $this->data = $data;
0057     }
0058 
0059     /**
0060      * Init from given URL
0061      *
0062      * @param  string $url
0063      * @return \Intervention\Image\Image
0064      */
0065     public function initFromUrl($url)
0066     {
0067         
0068         $options = [
0069             'http' => [
0070                 'method'=>"GET",
0071                 'header'=>"Accept-language: en\r\n".
0072                 "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2\r\n"
0073           ]
0074         ];
0075         
0076         $context  = stream_context_create($options);
0077         
0078 
0079         if ($data = @file_get_contents($url, false, $context)) {
0080             return $this->initFromBinary($data);
0081         }
0082 
0083         throw new \Intervention\Image\Exception\NotReadableException(
0084             "Unable to init from given url (".$url.")."
0085         );
0086     }
0087 
0088     /**
0089      * Init from given stream
0090      *
0091      * @param StreamInterface|resource $stream
0092      * @return \Intervention\Image\Image
0093      */
0094     public function initFromStream($stream)
0095     {
0096         if (!$stream instanceof StreamInterface) {
0097             $stream = new Stream($stream);
0098         }
0099 
0100         try {
0101             $offset = $stream->tell();
0102         } catch (\RuntimeException $e) {
0103             $offset = 0;
0104         }
0105 
0106         $shouldAndCanSeek = $offset !== 0 && $stream->isSeekable();
0107 
0108         if ($shouldAndCanSeek) {
0109             $stream->rewind();
0110         }
0111 
0112         try {
0113             $data = $stream->getContents();
0114         } catch (\RuntimeException $e) {
0115             $data = null;
0116         }
0117 
0118         if ($shouldAndCanSeek) {
0119             $stream->seek($offset);
0120         }
0121 
0122         if ($data) {
0123             return $this->initFromBinary($data);
0124         }
0125 
0126         throw new \Intervention\Image\Exception\NotReadableException(
0127             "Unable to init from given stream"
0128         );
0129     }
0130 
0131     /**
0132      * Determines if current source data is GD resource
0133      *
0134      * @return boolean
0135      */
0136     public function isGdResource()
0137     {
0138         if (is_resource($this->data)) {
0139             return (get_resource_type($this->data) == 'gd');
0140         }
0141 
0142         return false;
0143     }
0144 
0145     /**
0146      * Determines if current source data is Imagick object
0147      *
0148      * @return boolean
0149      */
0150     public function isImagick()
0151     {
0152         return is_a($this->data, 'Imagick');
0153     }
0154 
0155     /**
0156      * Determines if current source data is Intervention\Image\Image object
0157      *
0158      * @return boolean
0159      */
0160     public function isInterventionImage()
0161     {
0162         return is_a($this->data, '\Intervention\Image\Image');
0163     }
0164 
0165     /**
0166      * Determines if current data is SplFileInfo object
0167      *
0168      * @return boolean
0169      */
0170     public function isSplFileInfo()
0171     {
0172         return is_a($this->data, 'SplFileInfo');
0173     }
0174 
0175     /**
0176      * Determines if current data is Symfony UploadedFile component
0177      *
0178      * @return boolean
0179      */
0180     public function isSymfonyUpload()
0181     {
0182         return is_a($this->data, 'Symfony\Component\HttpFoundation\File\UploadedFile');
0183     }
0184 
0185     /**
0186      * Determines if current source data is file path
0187      *
0188      * @return boolean
0189      */
0190     public function isFilePath()
0191     {
0192         if (is_string($this->data)) {
0193             try {
0194                 return is_file($this->data);
0195             } catch (\Exception $e) {
0196                 return false;
0197             }
0198         }
0199 
0200         return false;
0201     }
0202 
0203     /**
0204      * Determines if current source data is url
0205      *
0206      * @return boolean
0207      */
0208     public function isUrl()
0209     {
0210         return (bool) filter_var($this->data, FILTER_VALIDATE_URL);
0211     }
0212 
0213     /**
0214      * Determines if current source data is a stream resource
0215      *
0216      * @return boolean
0217      */
0218     public function isStream()
0219     {
0220         if ($this->data instanceof StreamInterface) return true;
0221         if (!is_resource($this->data)) return false;
0222         if (get_resource_type($this->data) !== 'stream') return false;
0223 
0224         return true;
0225     }
0226 
0227     /**
0228      * Determines if current source data is binary data
0229      *
0230      * @return boolean
0231      */
0232     public function isBinary()
0233     {
0234         if (is_string($this->data)) {
0235             $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $this->data);
0236             return (substr($mime, 0, 4) != 'text' && $mime != 'application/x-empty');
0237         }
0238 
0239         return false;
0240     }
0241 
0242     /**
0243      * Determines if current source data is data-url
0244      *
0245      * @return boolean
0246      */
0247     public function isDataUrl()
0248     {
0249         $data = $this->decodeDataUrl($this->data);
0250 
0251         return is_null($data) ? false : true;
0252     }
0253 
0254     /**
0255      * Determines if current source data is base64 encoded
0256      *
0257      * @return boolean
0258      */
0259     public function isBase64()
0260     {
0261         if (!is_string($this->data)) {
0262             return false;
0263         }
0264 
0265         return base64_encode(base64_decode($this->data)) === $this->data;
0266     }
0267 
0268     /**
0269      * Initiates new Image from Intervention\Image\Image
0270      *
0271      * @param  Image $object
0272      * @return \Intervention\Image\Image
0273      */
0274     public function initFromInterventionImage($object)
0275     {
0276         return $object;
0277     }
0278 
0279     /**
0280      * Parses and decodes binary image data from data-url
0281      *
0282      * @param  string $data_url
0283      * @return string
0284      */
0285     private function decodeDataUrl($data_url)
0286     {
0287         if (!is_string($data_url)) {
0288             return null;
0289         }
0290 
0291         $pattern = "/^data:(?:image\/[a-zA-Z\-\.]+)(?:charset=\".+\")?;base64,(?P<data>.+)$/";
0292         preg_match($pattern, $data_url, $matches);
0293 
0294         if (is_array($matches) && array_key_exists('data', $matches)) {
0295             return base64_decode($matches['data']);
0296         }
0297 
0298         return null;
0299     }
0300 
0301     /**
0302      * Initiates new image from mixed data
0303      *
0304      * @param  mixed $data
0305      * @return \Intervention\Image\Image
0306      */
0307     public function init($data)
0308     {
0309         $this->data = $data;
0310 
0311         switch (true) {
0312 
0313             case $this->isGdResource():
0314                 return $this->initFromGdResource($this->data);
0315 
0316             case $this->isImagick():
0317                 return $this->initFromImagick($this->data);
0318 
0319             case $this->isInterventionImage():
0320                 return $this->initFromInterventionImage($this->data);
0321 
0322             case $this->isSplFileInfo():
0323                 return $this->initFromPath($this->data->getRealPath());
0324 
0325             case $this->isBinary():
0326                 return $this->initFromBinary($this->data);
0327 
0328             case $this->isUrl():
0329                 return $this->initFromUrl($this->data);
0330 
0331             case $this->isStream():
0332                 return $this->initFromStream($this->data);
0333 
0334             case $this->isDataUrl():
0335                 return $this->initFromBinary($this->decodeDataUrl($this->data));
0336 
0337             case $this->isFilePath():
0338                 return $this->initFromPath($this->data);
0339 
0340             // isBase64 has to be after isFilePath to prevent false positives
0341             case $this->isBase64():
0342                 return $this->initFromBinary(base64_decode($this->data));
0343 
0344             default:
0345                 throw new Exception\NotReadableException("Image source not readable");
0346         }
0347     }
0348 
0349     /**
0350      * Decoder object transforms to string source data
0351      *
0352      * @return string
0353      */
0354     public function __toString()
0355     {
0356         return (string) $this->data;
0357     }
0358 }