255 lines
		
	
	
		
			No EOL
		
	
	
		
			4.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			No EOL
		
	
	
		
			4.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace kcfinder;
 | 
						|
 | 
						|
/**
 | 
						|
 * FastImage - Because sometimes you just want the size!
 | 
						|
 * Based on the Ruby Implementation by Steven Sykes (https://github.com/sdsykes/fastimage)
 | 
						|
 *
 | 
						|
 * Copyright (c) 2012 Tom Moor
 | 
						|
 * Tom Moor, http://tommoor.com
 | 
						|
 *
 | 
						|
 * MIT Licensed
 | 
						|
 * @version 0.1
 | 
						|
 */
 | 
						|
 | 
						|
class fastImage
 | 
						|
{
 | 
						|
  private $strpos = 0;
 | 
						|
  private $str;
 | 
						|
  private $uri;
 | 
						|
  private $type;
 | 
						|
  private $handle;
 | 
						|
 | 
						|
  public function __construct($uri = null)
 | 
						|
  {
 | 
						|
    if ($uri) $this->load($uri);
 | 
						|
  }
 | 
						|
 | 
						|
  public function load($uri)
 | 
						|
  {
 | 
						|
    if ($this->handle) $this->close();
 | 
						|
 | 
						|
    $this->uri = $uri;
 | 
						|
    // Joy - this is a fix for URLs missing "http:"
 | 
						|
    if ($uri[0] == '/' && $uri[1] == '/') {
 | 
						|
      $uri = 'http:' . $uri;
 | 
						|
    }
 | 
						|
 | 
						|
    $this->handle = fopen(
 | 
						|
      $uri,
 | 
						|
      'r',
 | 
						|
      false,
 | 
						|
      stream_context_create(array(
 | 
						|
        'http'=> array('timeout' => 0.5),
 | 
						|
      ))
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  public function isValid()
 | 
						|
  {
 | 
						|
    return empty($this->handle) ? false : true;
 | 
						|
  }
 | 
						|
 | 
						|
  public function close()
 | 
						|
  {
 | 
						|
    if (is_resource($this->handle)) fclose($this->handle);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  public function getSize()
 | 
						|
  {
 | 
						|
    $this->strpos = 0;
 | 
						|
    if ($this->getType())
 | 
						|
    {
 | 
						|
      return array_values($this->parseSize());
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  public function getType()
 | 
						|
  {
 | 
						|
    $this->strpos = 0;
 | 
						|
 | 
						|
    if (!$this->type)
 | 
						|
    {
 | 
						|
      switch ($this->getChars(2))
 | 
						|
      {
 | 
						|
      case "BM":
 | 
						|
        return $this->type = 'bmp';
 | 
						|
      case "GI":
 | 
						|
        return $this->type = 'gif';
 | 
						|
      case chr(0xFF).chr(0xd8):
 | 
						|
        return $this->type = 'jpeg';
 | 
						|
      case chr(0x89).'P':
 | 
						|
        return $this->type = 'png';
 | 
						|
      default:
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return $this->type;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function parseSize()
 | 
						|
  {
 | 
						|
    $this->strpos = 0;
 | 
						|
 | 
						|
    switch ($this->type)
 | 
						|
    {
 | 
						|
    case 'png':
 | 
						|
      return $this->parseSizeForPNG();
 | 
						|
    case 'gif':
 | 
						|
      return $this->parseSizeForGIF();
 | 
						|
    case 'bmp':
 | 
						|
      return $this->parseSizeForBMP();
 | 
						|
    case 'jpeg':
 | 
						|
      return $this->parseSizeForJPEG();
 | 
						|
    }
 | 
						|
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function parseSizeForPNG()
 | 
						|
  {
 | 
						|
    $chars = $this->getChars(25);
 | 
						|
 | 
						|
    return unpack("N*", substr($chars, 16, 8));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function parseSizeForGIF()
 | 
						|
  {
 | 
						|
    $chars = $this->getChars(11);
 | 
						|
 | 
						|
    return unpack("S*", substr($chars, 6, 4));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function parseSizeForBMP()
 | 
						|
  {
 | 
						|
    $chars = $this->getChars(29);
 | 
						|
    $chars = substr($chars, 14, 14);
 | 
						|
    $type = unpack('C', $chars);
 | 
						|
 | 
						|
    return (reset($type) == 40) ? unpack('L*', substr($chars, 4)) : unpack('L*', substr($chars, 4, 8));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function parseSizeForJPEG()
 | 
						|
  {
 | 
						|
    $state = null;
 | 
						|
    $i = 0;
 | 
						|
 | 
						|
    while (true)
 | 
						|
    {
 | 
						|
      switch ($state)
 | 
						|
      {
 | 
						|
      default:
 | 
						|
        $this->getChars(2);
 | 
						|
        $state = 'started';
 | 
						|
        break;
 | 
						|
      case 'started':
 | 
						|
        $b = $this->getByte();
 | 
						|
        if ($b === false) return false;
 | 
						|
 | 
						|
        $state = $b == 0xFF ? 'sof' : 'started';
 | 
						|
        break;
 | 
						|
 | 
						|
      case 'sof':
 | 
						|
        $b = $this->getByte();
 | 
						|
        if (in_array($b, range(0xe0, 0xef)))
 | 
						|
        {
 | 
						|
          $state = 'skipframe';
 | 
						|
        }
 | 
						|
        elseif (in_array($b, array_merge(range(0xC0,0xC3), range(0xC5,0xC7), range(0xC9,0xCB), range(0xCD,0xCF))))
 | 
						|
        {
 | 
						|
          $state = 'readsize';
 | 
						|
        }
 | 
						|
        elseif ($b == 0xFF)
 | 
						|
        {
 | 
						|
          $state = 'sof';
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          $state = 'skipframe';
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case 'skipframe':
 | 
						|
        $skip = $this->readInt($this->getChars(2)) - 2;
 | 
						|
        $state = 'doskip';
 | 
						|
        break;
 | 
						|
 | 
						|
      case 'doskip':
 | 
						|
        $this->getChars($skip);
 | 
						|
        $state = 'started';
 | 
						|
        break;
 | 
						|
 | 
						|
      case 'readsize':
 | 
						|
        $c = $this->getChars(7);
 | 
						|
 | 
						|
        return array($this->readInt(substr($c, 5, 2)), $this->readInt(substr($c, 3, 2)));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function getChars($n)
 | 
						|
  {
 | 
						|
    $response = null;
 | 
						|
 | 
						|
    // do we need more data?
 | 
						|
    if ($this->strpos + $n -1 >= strlen($this->str))
 | 
						|
    {
 | 
						|
      $end = ($this->strpos + $n);
 | 
						|
 | 
						|
      while (strlen($this->str) < $end && $response !== false)
 | 
						|
      {
 | 
						|
        // read more from the file handle
 | 
						|
        $need = $end - ftell($this->handle);
 | 
						|
 | 
						|
        if ($response = fread($this->handle, $need))
 | 
						|
        {
 | 
						|
          $this->str .= $response;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $result = substr($this->str, $this->strpos, $n);
 | 
						|
    $this->strpos += $n;
 | 
						|
 | 
						|
    return $result;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function getByte()
 | 
						|
  {
 | 
						|
    $c = $this->getChars(1);
 | 
						|
    $b = unpack("C", $c);
 | 
						|
 | 
						|
    return reset($b);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  private function readInt($str)
 | 
						|
  {
 | 
						|
    $size = unpack("C*", $str);
 | 
						|
 | 
						|
    return ($size[1] << 8) + $size[2];
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  public function __destruct()
 | 
						|
  {
 | 
						|
    $this->close();
 | 
						|
  }
 | 
						|
} |