home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 March / PCWorld_2003-03_cd.bin / Software / Vyzkuste / phptriad / phptriad2-2-1.exe / php / pear / Image / Remote.php
Encoding:
PHP Script  |  2001-08-13  |  16.0 KB  |  526 lines

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  4. // +----------------------------------------------------------------------+
  5. // | PHP version 4.0                                                      |
  6. // +----------------------------------------------------------------------+
  7. // | Copyright (c) 1997-2001 The PHP Group                                |
  8. // +----------------------------------------------------------------------+
  9. // | This source file is subject to version 2.0 of the PHP license,       |
  10. // | that is bundled with this package in the file LICENSE, and is        |
  11. // | available at through the world-wide-web at                           |
  12. // | http://www.php.net/license/2_02.txt.                                 |
  13. // | If you did not receive a copy of the PHP license and are unable to   |
  14. // | obtain it through the world-wide-web, please send a note to          |
  15. // | license@php.net so we can mail you a copy immediately.               |
  16. // +----------------------------------------------------------------------+
  17. // | Authors: Mika Tuupola <tuupola@appelsiini.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Remote.php,v 1.6 2001/08/13 13:31:24 tuupola Exp $
  21.  
  22. define("GIF_SIGNATURE_LENGTH",      3);
  23. define("GIF_VERSION_LENGTH",        3);
  24. define("GIF_LSW_LENGTH",            2);
  25. define("GIF_LSH_LENGTH",            2);
  26.  
  27. define("PNG_SIGNATURE_LENGTH",      8);
  28. define("PNG_IHDR_LENGTH_LENGTH",    4);
  29. define("PNG_IHDR_CHUNKTYPE_LENGTH", 4);
  30. define("PNG_IHDR_IMW_LENGTH",       4);
  31. define("PNG_IHDR_IMH_LENGTH",       4);
  32.  
  33. define("JPG_PARAM_LENGTH_LENGTH",   2);
  34. define("JPG_DATA_PRECISION_LENGTH", 1);
  35. define("JPG_IMW_LENGTH_LENGTH",     2);
  36. define("JPG_IMH_LENGTH_LENGTH",     2);
  37. define("JPG_NUM_COMPONENTS_LENGTH", 1);
  38.  
  39. // The following jpeg defines were taken from rdjpgcom.c, which is part
  40. // of the Independent JPEG Group's software.
  41. // Copyright (C) 1994-1997, Thomas G. Lane.
  42. //
  43. // ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
  44.  
  45. define("M_SOF0",  0xC0);   /* Start Of Frame N */
  46. define("M_SOF1",  0xC1);   /* N indicates which compression process */
  47. define("M_SOF2",  0xC2);   /* Only SOF0-SOF2 are now in common use */
  48. define("M_SOF3",  0xC3);
  49. define("M_SOF5",  0xC5);   /* NB: codes C4 and CC are NOT SOF markers */
  50. define("M_SOF6",  0xC6);
  51. define("M_SOF7",  0xC7);
  52. define("M_SOF9",  0xC9);
  53. define("M_SOF10", 0xCA);
  54. define("M_SOF11", 0xCB);
  55. define("M_SOF13", 0xCD);
  56. define("M_SOF14", 0xCE);
  57. define("M_SOF15", 0xCF);
  58. define("M_SOI",   0xD8);   /* Start Of Image (beginning of datastream) */
  59. define("M_EOI",   0xD9);   /* End Of Image (end of datastream) */
  60. define("M_SOS",   0xDA);   /* Start Of Scan (begins compressed data) */
  61. define("M_APP0",  0xE0);   /* Application-specific marker, type N */
  62. define("M_APP12", 0xEC);   /* (we don't bother to list all 16 APPn's) */
  63. define("M_COM",   0xFE);   /* COMment */
  64.  
  65. require_once('PEAR.php');
  66.  
  67. /**
  68.   * Image_Remote - retrieve size from remote image files.
  69.   *
  70.   * Class can be used to get size information from remote 
  71.   * image files without downloading the whole image file. 
  72.   * It mimics the GetImageSize() PHP function but works on  
  73.   * remote images. Gif, jpeg and png currently supported. 
  74.   * 
  75.   * NOTE: Since PHP 4.0.5 URL support was added also to PHP's native
  76.   * GetImageSize().
  77.   *
  78.   * Usage:
  79.   *   
  80.   *   $i = new Image_Remote("http://www.example.com/test.png");
  81.   *   if (PEAR::isError($i)) {
  82.   *       print "ERROR: " . $i->getMessage();
  83.   *   } else { 
  84.   *       $data = $i->getImageSize();
  85.   *   }
  86.   *   
  87.   *
  88.   * @access public
  89.   * @author Mika Tuupola <tuupola@appelsiini.net>
  90.   * @version $Revision: 1.6 $
  91.   */
  92.  
  93.  
  94. class Image_Remote
  95. {
  96.  
  97.   /**
  98.     * The URL to fetch size from
  99.     *
  100.     * @var  string
  101.     */
  102.     var $url;         
  103.  
  104.   /**
  105.     * Parsed URL
  106.     *
  107.     * @var  array
  108.     */
  109.     var $purl;  
  110.  
  111.   /**
  112.     * Filesize of the remote image
  113.     *
  114.     * @var  integer
  115.     */      
  116.  
  117.     var $filesize;    // filesize of the remote file
  118.  
  119.   /**
  120.     * Mimetype of the remote image
  121.     *
  122.     * @var  string
  123.     */
  124.     var $mimetype;   
  125.  
  126.   /**
  127.     * Imagetype of the remote image
  128.     *
  129.     * @var  integer
  130.     */
  131.     var $imagetype;  
  132.  
  133.   /**
  134.     * Width of the remote image
  135.     *
  136.     * @var  integer
  137.     */
  138.     var $width;       // image width
  139.  
  140.   /**
  141.     * Height of the remote image
  142.     *
  143.     * @var  integer
  144.     */
  145.     var $height;      // image height
  146.  
  147.   /**
  148.     * Some useless extrainfo
  149.     *
  150.     * @var  string
  151.     */
  152.     var $extra;       // some useless extrainfo
  153.  
  154.  
  155.   /**
  156.     * Error of the last method call
  157.     *
  158.     * @var  string
  159.     */
  160.     var $errstr;      // error of the last method call
  161.  
  162.   /**
  163.     * Constructor
  164.     * 
  165.     * @param     string     foo URL of the remote image. Currently supports only http.
  166.     * @return     object
  167.     *
  168.     */
  169.  
  170.     function Image_Remote($input) 
  171.     {
  172.         $this->purl = parse_url($input);  
  173.  
  174.         if ($this->purl[scheme] == 'http') {
  175.             $this->url = $input;
  176.  
  177.             // assign default port if not given
  178.             if (!($this->purl[port])) {
  179.                 $this->purl[port] = 80;
  180.             }
  181.             $this->errstr = "";
  182.             // actually fetch the info
  183.             Image_Remote::_fetchImageInfo();
  184.  
  185.         } else {
  186.             $this->errstr = "Only http supported.";
  187.         }
  188.     
  189.         if ($this->errstr) {
  190.             $this = new PEAR_Error($this->errstr);
  191.         }
  192.  
  193.     } // constructor
  194.  
  195.   
  196.   /**
  197.     * Return information on the remote image. 
  198.     *
  199.     * Imitates PHP's native GetImageSize. 
  200.     * 
  201.     * http://www.php.net/manual/function.getimagesize.php  
  202.     *
  203.     * @access     public
  204.     * @return     array 
  205.     */
  206.     function getImageSize() 
  207.     {
  208.         $retval = array(0,0,0,"");
  209.  
  210.         $retval[0] = $this->width;  
  211.         $retval[1] = $this->height;  
  212.         $retval[2] = $this->imagetype;
  213.         $retval[3] = "WIDTH=\"$retval[0]\" HEIGHT=\"$retval[1]\"";
  214.  
  215.         return($retval);   
  216.     }
  217.  
  218.   /**
  219.     * Return the URL of the remote image. 
  220.     *
  221.     * This is actually the same URL which was given to the constructor.  
  222.     * However it sometimes comes handy to be able to retrieve the URL  
  223.     * again from the object. 
  224.     * 
  225.     * @access    public
  226.     * @return     string
  227.     */
  228.  
  229.     function getImageURL() 
  230.     {
  231.         $retval = $this->url;
  232.         return($retval);
  233.     }
  234.  
  235.   /**
  236.     * Fetch information of the remote image. 
  237.     *
  238.     * @access    private
  239.     * @return     boolean
  240.     */
  241.     function _fetchImageInfo() 
  242.     {
  243.  
  244.         // default to success.
  245.         $retval = 1;
  246.         // Open the connection and get the headers
  247.         $fp = fsockopen ($this->purl[host], $this->purl[port], &$errno, &$errstr, 30);
  248.         if (!$fp) {
  249.             $this->errstr = "Could not open socket $errstr ($errno)\n";
  250.             $retval = 0;
  251.         } else {
  252.  
  253.             // get the headers.
  254.             fputs ($fp, "GET " . $this->purl[path] . $this->purl[query] . " HTTP/1.1\r\n");
  255.             fputs ($fp, "Host: " . $this->purl[host] . "\r\n");
  256.             fputs ($fp, "User-Agent: Image_Remote PHP Class\r\n");
  257.             fputs ($fp, "Connection: close\r\n\r\n");
  258.             $line = trim(fgets($fp,128));
  259.             while ($line) {
  260.                 // Extract redirection
  261.                 if (preg_match("/^HTTP\/1\.[0-1] (3[0-9][0-9] .*)/", $line, $matches)) {
  262.                     $this->errstr = $matches[1] . " not implemented yet!";
  263.                     $retval = 0;
  264.                 }
  265.                 // Extract client error
  266.                     if (preg_match("/^HTTP\/1\.[0-1] (4[0-9][0-9] .*)/", $line, $matches)) {
  267.                     $this->errstr = $matches[1];
  268.                     $retval = 0;
  269.                 }
  270.                 // Extract server error
  271.                 if (preg_match("/^HTTP\/1\.[0-1] (5[0-9][0-9] .*)/", $line, $matches)) {
  272.                     $this->errstr = $matches[1];
  273.                     $retval = 0;
  274.                 }
  275.                 // Extract mime type
  276.                 if (preg_match("/Content-Type: (.*)/", $line, $matches)) {
  277.                     $tempmime = chop($matches[1]);
  278.                 }
  279.                 // Extract filesize
  280.                  if (preg_match("/Content-Length: ([0-9]*)/", $line, $matches)) {
  281.                    $tempfilesize = $matches[1];
  282.                 }
  283.                 $line = trim(fgets($fp,128));
  284.             }
  285.  
  286.             // If we got correct mimetype etc (we trust what the webserver says), 
  287.             // continue to fetch the actual data. 
  288.       
  289.             // if no error yet
  290.             if ($retval) {
  291.             // if correct mimetype
  292.                 if (preg_match("/image\/(gif|jpeg|x-jpeg|x-png|png)/", $tempmime)) {
  293.                     $this->mimetype = $tempmime;
  294.                     $this->filesize = $tempfilesize;
  295.  
  296.                     SWITCH ($tempmime) {
  297.                         case 'image/gif':
  298.                             Image_Remote::_fetchAndParseGIFHeader($fp);
  299.                             $this->imagetype = 1;
  300.                             break;
  301.                         case 'image/png':
  302.                         case 'image/x-png':
  303.                             Image_Remote::_fetchAndParsePNGHeader($fp);
  304.                             $this->imagetype = 3;
  305.                             break;
  306.                         case 'image/jpeg':
  307.                         case 'image/x-jpeg':
  308.                             Image_Remote::_fetchAndParseJPGHeader($fp);
  309.                             $this->imagetype = 2;
  310.                             break;
  311.                     }
  312.  
  313.                 } else {
  314.                     $this->errstr = "Unsupported mimetype $tempmime.";
  315.                     $retval = 0;
  316.                 }
  317.             } 
  318.             fclose($fp);
  319.         }
  320.         return($retval);
  321.     } // _fetchImageInfo
  322.  
  323.  
  324.   /**
  325.     * Parse GIF header
  326.     *
  327.     * @access    private
  328.     * @return     void
  329.     */
  330.     function _fetchAndParseGIFHeader($fd) 
  331.     {
  332.         if (!$fd) {
  333.             $this->errstr = "No socket.";
  334.         } else {
  335.             $signature = fread($fd, GIF_SIGNATURE_LENGTH);
  336.             $version   = fread($fd, GIF_VERSION_LENGTH);
  337.             $wbytes    = fread($fd, GIF_LSW_LENGTH);
  338.             $hbytes    = fread($fd, GIF_LSH_LENGTH);
  339.  
  340.             // Host Byte Order
  341.             $this->width  = Image_Remote::_htodecs($wbytes);
  342.             $this->height = Image_Remote::_htodecs($hbytes);
  343.  
  344.             $this->extra  = $signature . $version;    
  345.         }
  346.     }
  347.  
  348.   /**
  349.     * Parse PNG header
  350.     *
  351.     * @access    private
  352.     * @return     void
  353.     */
  354.     function _fetchAndParsePNGHeader($fd) 
  355.     {
  356.  
  357.         if (!$fd) {
  358.             $this->errstr = "No socket.";
  359.         } else {
  360.             $signature = fread($fd, PNG_SIGNATURE_LENGTH);
  361.             $ihdrl     = fread($fd, PNG_IHDR_LENGTH_LENGTH);
  362.             $ihdrct    = fread($fd, PNG_IHDR_CHUNKTYPE_LENGTH);
  363.             $wbytes    = fread($fd, PNG_IHDR_IMW_LENGTH);
  364.             $hbytes    = fread($fd, PNG_IHDR_IMH_LENGTH);
  365.  
  366.             // Network Byte Order
  367.             $this->width  = Image_Remote::_ntodecl($wbytes);
  368.             $this->height = Image_Remote::_ntodecl($hbytes);
  369.  
  370.             $this->extra  = $signature;       
  371.         }
  372.     }
  373.  
  374.     // The jpeg parser is basically port of code found from rdjpgcom.c, 
  375.     // which is  part of the Independent JPEG Group's software.
  376.     // Copyright (C) 1994-1997, Thomas G. Lane.
  377.     //
  378.     // ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
  379.     //
  380.     // Similar port can be found in elqGetImageFormat() by Oyvind Hallsteinsen 
  381.     //
  382.     // ftp://ftp.elq.org/pub/php3/elqGetImageFormat/elqGetImageFormat.php3
  383.  
  384.   /**
  385.     * Parse JPEG header
  386.     *
  387.     * @access    private
  388.     * @return     void
  389.     */
  390.     function _fetchAndParseJPGHeader($fd) 
  391.     {
  392.  
  393.         if (!$fd) {
  394.             $this->errstr = "No socket.";
  395.         } else {
  396.             $done = 0;
  397.  
  398.             // first marker
  399.             $c1 = ord(fread($fd, 1));
  400.             $c2 = ord(fread($fd, 1));
  401.             if ($c1 != 0xFF || $c2 != M_SOI) {
  402.                 $this->errstr="Not a jpeg file?";
  403.             } else { 
  404.  
  405.                 while (!($done)) {
  406.         
  407.                     // find next marker
  408.                     $marker = ord(fread($fd, 1));
  409.                     while ($marker != 0xFF) {
  410.                         $marker = ord(fread($fd, 1));
  411.                     }   
  412.                     do {
  413.                         $marker = ord(fread($fd, 1));
  414.                     } while ($marker == 0xFF);
  415.  
  416.                     SWITCH ($marker) {
  417.                         case M_SOF0:
  418.                         case M_SOF1:
  419.                         case M_SOF2:
  420.                         case M_SOF3:
  421.                         case M_SOF5:
  422.                         case M_SOF6:
  423.                         case M_SOF7:
  424.                         case M_SOF9: 
  425.                         case M_SOF10:
  426.                         case M_SOF11:
  427.                         case M_SOF13:
  428.                         case M_SOF14:
  429.                         case M_SOF15:
  430.                             $length    = fread($fd, JPG_PARAM_LENGTH_LENGTH);
  431.                             $precision = fread($fd, JPG_DATA_PRECISION_LENGTH);
  432.                             $hbytes    = fread($fd, JPG_IMH_LENGTH_LENGTH);
  433.                             $wbytes    = fread($fd, JPG_IMW_LENGTH_LENGTH);
  434.                             $components= fread($fd, JPG_NUM_COMPONENTS_LENGTH);
  435.                
  436.                             // Network Byte Order
  437.                             $this->width  = Image_Remote::_ntodecs($wbytes);
  438.                             $this->height = Image_Remote::_ntodecs($hbytes);
  439.                          
  440.                             $this->extra  = "";
  441.                             $done = 1;
  442.                             break; 
  443.                         case M_SOS:  
  444.                             $done = 1; 
  445.                             break;
  446.  
  447.                         // By default we skip over unwanted markers and avoid
  448.                         // being fooled by 0xFF bytes in parameter segment.
  449.                         default:
  450.                             $lbytes = fread($fd, JPG_PARAM_LENGTH_LENGTH);
  451.                             $length = Image_Remote::_ntodecs($lbytes); 
  452.                             if ($length < JPG_PARAM_LENGTH_LENGTH) {
  453.                                 $this->errstr="Erronous parameter length.";
  454.                                 $done = 1;
  455.                             } 
  456.                             // the length is included in param length and
  457.                             // allready read
  458.                             $length -= JPG_PARAM_LENGTH_LENGTH;
  459.                             fread($fd, $length);
  460.                             break;
  461.                     }    
  462.                 }
  463.             }
  464.         }
  465.     }
  466.  
  467.   /**
  468.     * Host byte order to decimal long
  469.     *
  470.     * @access    private
  471.     * @return     integer
  472.     */
  473.     function _htodecl($bytes) 
  474.     {
  475.         $b1 = ord($bytes[0]);
  476.         $b2 = (ord($bytes[1])<<8);
  477.         $b3 = (ord($bytes[2])<<16);
  478.         $b4 = (ord($bytes[3])<<24);
  479.         return($b1 + $b2 + $b3 + $b4);
  480.     }
  481.  
  482.   /**
  483.     * Host byte order to decimal short
  484.     *
  485.     * @access    private
  486.     * @return     integer
  487.     */
  488.     function _htodecs($bytes) 
  489.     {
  490.         $b1 = ord($bytes[0]);
  491.         $b2 = (ord($bytes[1]) << 8);
  492.         return($b1 + $b2);
  493.     }
  494.  
  495.   /**
  496.     * Network byte order to decimal long
  497.     *
  498.     * @access    private
  499.     * @return     integer
  500.     */
  501.     function _ntodecl($bytes) 
  502.     {
  503.         $b1 = ord($bytes[3]);
  504.         $b2 = (ord($bytes[2]) << 8);
  505.         $b3 = (ord($bytes[1]) << 16);
  506.         $b4 = (ord($bytes[0]) << 24);
  507.         return($b1 + $b2 + $b3 + $b4); 
  508.     }
  509.  
  510.   /**
  511.     * Network byte order to decimal short
  512.     *
  513.     * @access    private
  514.     * @return     integer
  515.     */
  516.     function _ntodecs($bytes) 
  517.     {
  518.         $b1 = ord($bytes[1]);
  519.         $b2 = (ord($bytes[0]) << 8 );
  520.         return($b1 + $b2);
  521.     }
  522.  
  523. } // class 
  524.  
  525. ?>
  526.