home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / Image / Remote.php
PHP Script  |  2001-01-16  |  15KB  |  396 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.3 2001/01/16 14:59:01 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. class Image_Remote 
  66. {
  67.     var $url;         // the url we should be handling
  68.     var $purl;        // parsed url
  69.     var $filesize;    // filesize of the remote file
  70.     var $mimetype;    // mimetype of the remote url
  71.     var $imagetype;   // imagetype
  72.     var $width;       // image width
  73.     var $height;      // image height
  74.     var $extra;       // some useless extrainfo
  75.     var $errstr;      // error of the last method call
  76.  
  77.     /**
  78.      * Image_Remote is a class to retrieve information on remote
  79.      * imagefiles without actually downloading the whole image.
  80.      * It mimics the GetImageSize() PHP function but works on 
  81.      * remote images. Gif, jpeg and png currently supported.
  82.      *
  83.      * Usage:
  84.      *
  85.      *   $i = new Image_Remote("http://www.example.com/test.png");
  86.      *   $data = $i->getImageSize();
  87.      *
  88.      * @param string $input URL of the remote image. Currently supports 
  89.      *        only http.
  90.      *
  91.      * @author Mika Tuupola <tuupola@appelsiini.net>
  92.      * @version $Revision: 1.3 $
  93.      */
  94.  
  95.     function Image_Remote($input) 
  96.     {
  97.         $this->purl = parse_url($input);  
  98.  
  99.         if ($this->purl[scheme] == 'http') {
  100.             $this->url = $input;
  101.  
  102.             // assign default port if not given
  103.             if (!($this->purl[port])) {
  104.                 $this->purl[port] = 80;
  105.             }
  106.             $this->errstr = "";
  107.             // actually fetch the info
  108.             Image_Remote::_fetchImageInfo();
  109.  
  110.         } else {
  111.             $this->errstr = "Only http supported.";
  112.         }
  113.     } // constructor
  114.  
  115.   
  116.     /**
  117.      * Gets information on the remote image. Imitates PHP's native 
  118.      * GetImageSize. 
  119.      * 
  120.      * http://www.php.net/manual/function.getimagesize.php  
  121.      *
  122.      * @return array where array[0] contains the width of the image,
  123.      *         array[1] contains the height of the image, array[2] contains
  124.      *         an integer indicating type of the image. 1 = GIF, 2 = JPG, 
  125.      *         3 = PNG. array[3] contains a string in WIDTH="X" HEIGHT="X" 
  126.      *         format.
  127.      */
  128.     function getImageSize() 
  129.     {
  130.         $retval = array(0,0,0,"");
  131.  
  132.         $retval[0] = $this->width;  
  133.         $retval[1] = $this->height;  
  134.         $retval[2] = $this->imagetype;
  135.         $retval[3] = "WIDTH=\"$retval[0]\" HEIGHT=\"$retval[1]\"";
  136.  
  137.         return($retval);   
  138.     }
  139.  
  140.     /**
  141.      * Gets the URL of the remote image. This is actually the same URL
  142.      * which was given to the constructor. However it sometimes comes
  143.      * handy to be able to retrieve the URL again from the object.
  144.      * 
  145.      * @return string URL
  146.      */
  147.     function getImageURL() 
  148.     {
  149.         $retval = $this->url;
  150.         return($retval);
  151.     }
  152.  
  153.     function _fetchImageInfo() 
  154.     {
  155.  
  156.         // default to success.
  157.         $retval = 1;
  158.         // Open the connection and get the headers
  159.         $fp = fsockopen ($this->purl[host], $this->purl[port], &$errno, &$errstr, 30);
  160.         if (!$fp) {
  161.             $this->errstr = "Could not open socket $errstr ($errno)\n";
  162.             $retval = 0;
  163.         } else {
  164.  
  165.             // get the headers.
  166.             fputs ($fp, "GET " . $this->purl[path] . $this->purl[query] . " HTTP/1.1\r\n");
  167.             fputs ($fp, "Host: " . $this->purl[host] . "\r\n");
  168.             fputs ($fp, "User-Agent: Image_Remote PHP Class\r\n");
  169.             fputs ($fp, "Connection: close\r\n\r\n");
  170.             $line = trim(fgets($fp,128));
  171.             while ($line) {
  172.                 // Extract redirection
  173.                 if (preg_match("/^HTTP\/1\.[0-1] (3[0-9][0-9] .*)/", $line, $matches)) {
  174.                     $this->errstr = $matches[1] . " not implemented yet!";
  175.                     $retval = 0;
  176.                 }
  177.                 // Extract client error
  178.                     if (preg_match("/^HTTP\/1\.[0-1] (4[0-9][0-9] .*)/", $line, $matches)) {
  179.                     $this->errstr = $matches[1];
  180.                     $retval = 0;
  181.                 }
  182.                 // Extract server error
  183.                 if (preg_match("/^HTTP\/1\.[0-1] (5[0-9][0-9] .*)/", $line, $matches)) {
  184.                     $this->errstr = $matches[1];
  185.                     $retval = 0;
  186.                 }
  187.                 // Extract mime type
  188.                 if (preg_match("/Content-Type: (.*)/", $line, $matches)) {
  189.                     $tempmime = chop($matches[1]);
  190.                 }
  191.                 // Extract filesize
  192.                  if (preg_match("/Content-Length: ([0-9]*)/", $line, $matches)) {
  193.                    $tempfilesize = $matches[1];
  194.                 }
  195.                 $line = trim(fgets($fp,128));
  196.             }
  197.  
  198.             // If we got correct mimetype etc (we trust what the webserver says), 
  199.             // continue to fetch the actual data. 
  200.       
  201.             // if no error yet
  202.             if ($retval) {
  203.             // if correct mimetype
  204.                 if (preg_match("/image\/(gif|jpeg|x-jpeg|x-png|png)/", $tempmime)) {
  205.                     $this->mimetype = $tempmime;
  206.                     $this->filesize = $tempfilesize;
  207.  
  208.                     SWITCH ($tempmime) {
  209.                         case 'image/gif':
  210.                             Image_Remote::_fetchAndParseGIFHeader($fp);
  211.                             $this->imagetype = 1;
  212.                             break;
  213.                         case 'image/png':
  214.                         case 'image/x-png':
  215.                             Image_Remote::_fetchAndParsePNGHeader($fp);
  216.                             $this->imagetype = 3;
  217.                             break;
  218.                         case 'image/jpeg':
  219.                         case 'image/x-jpeg':
  220.                             Image_Remote::_fetchAndParseJPGHeader($fp);
  221.                             $this->imagetype = 2;
  222.                             break;
  223.                     }
  224.  
  225.                 } else {
  226.                     $this->errstr = "Unsupported mimetype $tempmime.";
  227.                     $retval = 0;
  228.                 }
  229.             } 
  230.             fclose($fp);
  231.         }
  232.         return($retval);
  233.     } // _fetchImageInfo
  234.  
  235.  
  236.     function _fetchAndParseGIFHeader($fd) 
  237.     {
  238.         if (!$fd) {
  239.             $this->errstr = "No socket.";
  240.         } else {
  241.             $signature = fread($fd, GIF_SIGNATURE_LENGTH);
  242.             $version   = fread($fd, GIF_VERSION_LENGTH);
  243.             $wbytes    = fread($fd, GIF_LSW_LENGTH);
  244.             $hbytes    = fread($fd, GIF_LSH_LENGTH);
  245.  
  246.             // Host Byte Order
  247.             $this->width  = Image_Remote::_htodecs($wbytes);
  248.             $this->height = Image_Remote::_htodecs($hbytes);
  249.  
  250.             $this->extra  = $signature . $version;    
  251.         }
  252.     }
  253.  
  254.     function _fetchAndParsePNGHeader($fd) 
  255.     {
  256.  
  257.         if (!$fd) {
  258.             $this->errstr = "No socket.";
  259.         } else {
  260.             $signature = fread($fd, PNG_SIGNATURE_LENGTH);
  261.             $ihdrl     = fread($fd, PNG_IHDR_LENGTH_LENGTH);
  262.             $ihdrct    = fread($fd, PNG_IHDR_CHUNKTYPE_LENGTH);
  263.             $wbytes    = fread($fd, PNG_IHDR_IMW_LENGTH);
  264.             $hbytes    = fread($fd, PNG_IHDR_IMH_LENGTH);
  265.  
  266.             // Network Byte Order
  267.             $this->width  = Image_Remote::_ntodecl($wbytes);
  268.             $this->height = Image_Remote::_ntodecl($hbytes);
  269.  
  270.             $this->extra  = $signature;       
  271.         }
  272.     }
  273.  
  274.     // The jpeg parser is basically port of code found from rdjpgcom.c, 
  275.     // which is  part of the Independent JPEG Group's software.
  276.     // Copyright (C) 1994-1997, Thomas G. Lane.
  277.     //
  278.     // ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
  279.     //
  280.     // Similar port can be found in elqGetImageFormat() by Oyvind Hallsteinsen 
  281.     //
  282.     // ftp://ftp.elq.org/pub/php3/elqGetImageFormat/elqGetImageFormat.php3
  283.  
  284.     function _fetchAndParseJPGHeader($fd) 
  285.     {
  286.  
  287.         if (!$fd) {
  288.             $this->errstr = "No socket.";
  289.         } else {
  290.             $done = 0;
  291.  
  292.             // first marker
  293.             $c1 = ord(fread($fd, 1));
  294.             $c2 = ord(fread($fd, 1));
  295.             if ($c1 != 0xFF || $c2 != M_SOI) {
  296.                 $this->errstr="Not a jpeg file?";
  297.             } else { 
  298.  
  299.                 while (!($done)) {
  300.         
  301.                     // find next marker
  302.                     $marker = ord(fread($fd, 1));
  303.                     while ($marker != 0xFF) {
  304.                         $marker = ord(fread($fd, 1));
  305.                     }   
  306.                     do {
  307.                         $marker = ord(fread($fd, 1));
  308.                     } while ($marker == 0xFF);
  309.  
  310.                     SWITCH ($marker) {
  311.                         case M_SOF0:
  312.                         case M_SOF1:
  313.                         case M_SOF2:
  314.                         case M_SOF3:
  315.                         case M_SOF5:
  316.                         case M_SOF6:
  317.                         case M_SOF7:
  318.                         case M_SOF9: 
  319.                         case M_SOF10:
  320.                         case M_SOF11:
  321.                         case M_SOF13:
  322.                         case M_SOF14:
  323.                         case M_SOF15:
  324.                             $length    = fread($fd, JPG_PARAM_LENGTH_LENGTH);
  325.                             $precision = fread($fd, JPG_DATA_PRECISION_LENGTH);
  326.                             $hbytes    = fread($fd, JPG_IMH_LENGTH_LENGTH);
  327.                             $wbytes    = fread($fd, JPG_IMW_LENGTH_LENGTH);
  328.                             $components= fread($fd, JPG_NUM_COMPONENTS_LENGTH);
  329.                
  330.                             // Network Byte Order
  331.                             $this->width  = Image_Remote::_ntodecs($wbytes);
  332.                             $this->height = Image_Remote::_ntodecs($hbytes);
  333.                          
  334.                             $this->extra  = "";
  335.                             $done = 1;
  336.                             break; 
  337.                         case M_SOS:  
  338.                             $done = 1; 
  339.                             break;
  340.  
  341.                         // By default we skip over unwanted markers and avoid
  342.                         // being fooled by 0xFF bytes in parameter segment.
  343.                         default:
  344.                             $lbytes = fread($fd, JPG_PARAM_LENGTH_LENGTH);
  345.                             $length = Image_Remote::_ntodecs($lbytes); 
  346.                             if ($length < JPG_PARAM_LENGTH_LENGTH) {
  347.                                 $this->errstr="Erronous parameter length.";
  348.                                 $done = 1;
  349.                             } 
  350.                             // the length is included in param length and
  351.                             // allready read
  352.                             $length -= JPG_PARAM_LENGTH_LENGTH;
  353.                             fread($fd, $length);
  354.                             break;
  355.                     }    
  356.                 }
  357.             }
  358.         }
  359.     }
  360.  
  361.     function _htodecl($bytes) 
  362.     {
  363.         $b1 = ord($bytes[0]);
  364.         $b2 = (ord($bytes[1])<<8);
  365.         $b3 = (ord($bytes[2])<<16);
  366.         $b4 = (ord($bytes[3])<<24);
  367.         return($b1 + $b2 + $b3 + $b4);
  368.     }
  369.  
  370.     function _htodecs($bytes) 
  371.     {
  372.         $b1 = ord($bytes[0]);
  373.         $b2 = (ord($bytes[1]) << 8);
  374.         return($b1 + $b2);
  375.     }
  376.  
  377.     function _ntodecl($bytes) 
  378.     {
  379.         $b1 = ord($bytes[3]);
  380.         $b2 = (ord($bytes[2]) << 8);
  381.         $b3 = (ord($bytes[1]) << 16);
  382.         $b4 = (ord($bytes[0]) << 24);
  383.         return($b1 + $b2 + $b3 + $b4); 
  384.     }
  385.  
  386.     function _ntodecs($bytes) 
  387.     {
  388.         $b1 = ord($bytes[1]);
  389.         $b2 = (ord($bytes[0]) << 8 );
  390.         return($b1 + $b2);
  391.     }
  392.  
  393. } // class 
  394.  
  395. ?>
  396.