Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Possible to have PHP find dimensions of Flash movie? 1

Status
Not open for further replies.

Sleidia

Technical User
May 4, 2001
1,284
FR

Hi guys,

Out of despair, I'm asking the question although my guess is that it's impossible.

So, is it possible to have PHP find the width and height of Flash movie?

Thanks :)
 
you might be able to open the Flash movie within PHP as a jpeg (look up the image functions: and you can definitely open the movie as raw data and parse it yourself.

however, i might actually load it and get the size via javascript and let the browser do the work for me. a little inefficient, but it'd work.
 
Thanks progman1010 :)

I've found this but it detects the size of the main timeline instead of the real dimension of the flash export.

So, how do you read the raw data of a swf file with PHP?
When I open a swf file in a text editor, the whole thing is encrypted.

Lastly, I've found this : but I'm very reluctant to use the whole PEAR package just for this.
 
when you say the whole pear package - that should not be too daunting. it's the kind of thing that most php installations will have pre-installed anyway. the base class is little more than error handling. so in fact all you are adding on is the SWF class which is only 20kb.
 

OK, Jpadie ;)

I'd like to try your idea but I don't understand how to use Pear even after I read the documentation.

I'm using Appserv on my local machine and Pear is located at C:\appserv\php\pear\go-pear.php

When I run go-pear.php, it installs 4.5Mb of files.
Do I really need this??

If Pear is already pre-installed, why would I need to do this?

 
ooer...

can you get terminal/telnet/ssh access to your machine? i don't find that the go-pear installer is very stable - whereas the command line is dead easy to use.

i'm pretty sure the majority of that download is the graphical installer rather than operational files. my entire pear library (with loads of extensions and documentation/unit tests) is only 3.5MB.

my recollection is that go-pear installs some big (and old) libraries by default too.

in any event not all those files will ever be needed for each application. they will just sit there on your hard drive until needed. they won't be loaded into memory just for your flash app.

 
although actually, if you have successfully run go-pear, you;ve done pretty much all that is necessary.

make sure that the php.ini includes a path to the pear directory. if you make changes to php.ini (and you're not running CGI) then restart your webserver.

then just download the swfreader. i'd install it in the pear directory tree, but there is no reason to do so.
 

wow ... I already want to give up ahaha ;)

Also, phpinfo shows include_path : .;c:\php4\pear

But, not only this directory doesn't exist, I can't find any reference to pear in php.ini!

So, how do I change this path?
And how will pear know where the packages can be found?

Sorry, no terminal/telnet/ssh access on my local comp.
 
if it's your local computer then of course you have terminal access! in windows it's called the DOS prompt!

so ... go change your php.ini file so that the include path points at your actual pear directory.

sometimes go-pear can put this in your webserver path. which is silly.

the actual whereabouts of pear (command line) will be different depending on your installation. from recollection, in windows, it is in a directory under the php executable.

once you've located the relevant directory see whether pear is there. if it is , then that's all you need to do (after changing the ini).

if it is not then there should be a file called go-pear.bat which will install pear for you. It will ask you some questions and you can just accept the default values (unless you want to change them). it will/should also drop a registry changer into the directory for you. run this to change your environmental variables to make pear easier to use.

then it's done (change the php.ini too).

then to install packages that reside in PEAR it's as simple as typing:
Code:
pear install --alldeps HTML_Quickform
for example (to install quickform).
 

OK, thanks... wew ;)
Everything went smooth but then I got this :

Code:
...pear install --alldeps FILE
WARNING: channel "pear.php.net" has updated its protocols, use "channel-update p
ear.php.net" to update
pear/File requires package "pear/PEAR" (version >= 1.5.3), installed version is
1.5.1
No valid packages found
install failed

I already have enough of it ahaha

Well, also I tried to just take out the useful functions from the Pear packages for PHP SWF READER to work but although it looks like nothing was missing, I got the following error :
Type C: not enough input, need 1, have 0

So, I'm starting to think that their stuff wouldn't work even if I correctly installed Pear.

Thanks for your time anyway :)
 
no don't give up. that's fine. you just have an old installation of pear on your system

type
Code:
pear channel-update

to tell pear where to get its new information from

then
Code:
pear upgrade-all

so that it can upgrade itself.

then you should be fine.

personally i've never used FILE. i've always found that php's inbuilt file handling was just fine.
 

Thanks Jpadie :)

Now, everything works and the size detection works too.
But, to be honest, I don't feel comfortable at the use of this Pear application. It's like adding one more layer of complexity plus, I hate OOP code (because I don't understand it).

So, do you think it can be possible to make the swfreader code work without Pear?

 
Sleidia said:
So, do you think it can be possible to make the swfreader code work without Pear?

yes. i've ported the code to standalone in an idle moment. i have included an example of typical usage in lines 27 to 40

i've not tested it as i have no swf files on hand. post back if there are problems.

Code:
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at |
// | [URL unfurl="true"]http://www.php.net/license/2_02.txt.[/URL] |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Original Author <alessandro@sephiroth.it> |
// +----------------------------------------------------------------------+

/**
* Base SWF class
*
* This class requires the File PEAR.
* Read the SWF header informations and return an
* associative array with the property of the SWF File, the result array
* will contain framerate, framecount, background color, compression, filetype
* version and movie size.
* <code>
* <?php
* require_once "File/File_SWF.php";
* $file = "any_file.swf";
*
* $swf = &new File_SWF($file);
* if ($swf->isError){
* 	die($swf->getErrorMessages();
* }
* if($swf->isValid){
* 	$result = $swf->stat();
* 	print_r($result);
* }
* ?>
* </code>
* @author Alessandro Crugnola <alessandro@sephiroth.it>
* @access public
* @version 0.2
* @package File_SWF
*/
class File_SWF
{
    /**
    * current unpacked binary string
    * @var mixed
    */
    var $current = "";
    /**
    * internal pointer
    * @var integer
    */
    var $position = 0;
    /**
    * use zlib compression
    * @var boolean
    */
    var $compression = 0;
    /**
    * current position
    * @var integer
    */
    var $point = 0;
    /**
    * is a valid swf
    * @var boolean
    * @access private
    */
    var $isValid = 0;
    /**
    * stirng file name to parse
    * @var string
    */
    var $file = "";
    /**
    * determine if file is protected
    * @var boolean
    */
    var $protected = false;
    /**
    * password for protected files
    * @var mixed
    */
    var $password;

    /**
    * Deconstructor
    * does anything right now
    * @access public
    */
    function _File_SWF(){
    	
    }

	/**
	 * function to emulate the FILE::read method in the pear FILE package
	 * 
	 * @return $return: the required number of bytes from a file or a blank string
	 * @param $file string reference to the file to open and read
	 * @param $bytes number of bytes to read
	 */
	function fileRead($file, $bytes=NULL){
		$fh = fopen($file, 'rb');
		if (!$fh) {
			$this->raiseError('cannot read from '.$file, $php_errormsg);
			return '';
		}
		if (is_null($bytes)){
			$bytes = filesize($file);
		}
		$return = fread($fh, $bytes);
		fclose ($fh);
		return $return;
	}
	/**
	 * function to replace the write method of pear file package
	 * 
	 * @return $return bool.  returns true on success, false on failure.
	 * @param $file string - file name to be updated
	 * @param $contents string to write to the file
	 * @param $mode valid php file mode for read/write
	 */
	function fileWrite($file, $contents, $mode){
		$fh = fopen($file, $mode);
		if (!$fh) {
			$this->raiseError('cannot write to '.$file, $php_errormsg);
			return false;
		}
		fwrite($fh, $contents);
		fclose ($fh);
		return $return;
	}
	/**
	 * function to replace the pear error handler
	 * 
	 * @return void
	 * @param $error string of human readable, internally generated error
	 * @param $phpError the human readable php error message
	 */
	function raiseError($error, $phpError){
		$this->isError = true;
		$this->errorMessages[] = array($error, $phpError);
	}
	
	/**
	 * function to replace some error handling within PEAR
	 * 
	 * @return $return string - html formatted set of error messages
	 */
	function getErrorMessages(){
		$return = '';
		foreach ($this->errorMessages as $m){
			$return .= <<<HTML
<div class="errorMessage">
<h2>{$m[0]}</h2>
<p>PHP reported this error message: {$m[1]}</p>
</div>

HTML;
		}
		return $return;
	}
	/**
    * Costructor
    * creates a new SWF object
    * reads the given file and parse it
    * @param string $file file to parse
    * @access public
    */
    function File_SWF($file="")
    {
    	ini_set('track_errors', 'on');
        $this->compression = 0;
        $this->isValid = 0;
        $this->point = 0;
		$this->errorMessages = array();
		$this->isError = false;
        $this->file = $file;
        $head = $this->fileRead($this->file, 3);
        if($this->isError()){
            return $head;
        }
       
        if($head == "CWS"){
            $data = $this->fileRead($this->file, 8);
            $_data = gzuncompress($this->fileRead($this->file, filesize($this->file)));
            $data = $data . $_data;
            $this->data = $data;
            $this->compression = 1;
            $this->isValid = 1;
        } else if ($head == "FWS"){
            $this->data = $this->fileRead($this->file, filesize($this->file));
            $this->isValid = 1;
        } else {
            /**
            * invalid SWF file, or invalid head tag found
            */
            $this->isValid = 0;
        }
    }

    /**
    * Is a valid SWF file
    * @return boolean
    * @access public
    */
    function is_valid()
    {
        return $this->isValid;
    }

    /**
    * Return if swf file is protected from import
    * @return boolean
    * @access public
    */
    function getProtected()
    {
        if($this->getVersion() >= 8){
            $this->_seek(31);
        } else {
            $this->_seek(26);
        }
        $data = $this->_readTag();
        $tag  = $data[0];
        $this->protected = $tag == 24;
        return $this->protected;
    }

    /**
    * Define import protection for the SWF
    * @param boolean $protect define is file must be protected
    * @access public
    */
    function setProtected($protect)
    {
        if($protect and !$this->protected){
            if($this->getVersion() >= 8){
                $pre = substr($this->data, 0, 31);
                $post = substr($this->data, 31);
            } else {
                $pre = substr($this->data, 0, 26);
                $post = substr($this->data, 26);
            }
            $middle = pack("v", 1536);
            $this->data = $pre . $middle . $post;
            $this->password = 0;
            $this->protected = true;
        } else if(!$protect and $this->protected){
            if($this->getVersion() >= 8){
                $pos = 31;
            } else {
                $pos = 26;
            }
            $this->_seek($pos);
            if($this->_readData()){
                $this->data = substr($this->data,0, $pos) . substr($this->data, $this->point - (is_string($this->password) == 1 ? 0 : 1));
            }
        }
    }

    /**
    * Return the current SWF frame rate
    * @return mixed interger frame rate in fps or Error if invalid file
    * @access public
    */
    function getFrameRate()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        if($this->getVersion() >= 8){
            $this->_seek(16);
        } else {
            $this->_seek(17);
        }
        $fps = unpack('vrate',$this->_read(2));
        return $fps['rate']/256;
    }

    /**
    * Set the new Frame Rate
    * @access public
    */
    function setFrameRate($num)
    {
        if(!$this->is_valid()){
            return;
        }
        $num = intval($num);
        if($num > 0 and $num <= 120){
            $fps = pack('v', $num*256);
            if($this->getVersion() >= 8){
                $this->_seek(16);
                $this->data = substr($this->data, 0, 16) . $fps . substr($this->data, 18);
            } else {
                $this->_seek(17);
                $this->data = substr($this->data, 0, 17) . $fps . substr($this->data, 19);
            }
        }
    }

    /**
    * Return the current number of frames
    * @return mixed interger or error if invalid file format
    * @access public
    */
    function getFrameCount()
    {
        if(!$this->is_valid()){
             $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			 return;
        }
        if($this->getVersion() >= 8){
            $this->_seek(18);
        } else {
            $this->_seek(19);
        }
        return $this->_readshort();
    }

    /**
    * Return the current movie size in pixel
    * @return mixed array or error if invalid file format
    * @access public
    */
    function getMovieSize()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        $this->_seek(8);
        return $this->_readRect();
    }

    /**
    * Return the current file type (CWS, FWS)
    * @return mixed string or error if invalid file format
    * @access public
    */
    function getFileType()
    {
        if(!$this->is_valid()){
        	$this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        $this->_seek(0);
        return $this->_read(3);
    }

    /**
    * Return the current compression used
    * @return mixed interger or error if invalid file format
    * @access public
    */
    function getCompression()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
        	return;
		}
        return $this->compression;
    }

    /**
    * Set the compression
    * @return string based on the compression used
    * @param integer $mode compression on/off
    * @access public
    */
    function setCompression($mode = 0)
    {
        if(!$this->is_valid()){
            return;
        }
        $data = "";
        $real_size = pack( "V", strlen($this->data));
        $this->data = substr($this->data, 0, 4) . $real_size . substr($this->data, 8, strlen($this->data));
        if($mode == 0){
            $this->compression = 0;
            $this->data = "FWS" . substr($this->data, 3);
            $_n1 = substr($this->data, 0, 8);
            $_n2 = substr($this->data, 8, strlen($this->data));
            $data = $_n1 . $_n2;
        } else if($mode == 1){
            $this->compression = 1;
            $this->data = "CWS" . substr($this->data, 3);
            $_n1 = substr($this->data, 0, 8);
            $_n2 = substr($this->data, 8, strlen($this->data));
            $_n3 = gzcompress($_n2);
            $data = $_n1 . $_n3;
        }
        return $data;
    }

    /**
    * Return the current version of player used
    * @return mixed interger or error if invalid file format
    * @access public
    */
    function getVersion()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        $this->_seek(3);
        return $this->_readbyte();
    }

    /**
    * Return the current SWF file size
    * @return mixed interger or error if invalid file format
    * @access public
    */
    function filesize()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        $this->_seek(4);
        $real_size = unpack( "Vnum", $this->_read(4) );
        if( $this->getCompression() ){
            $n = $this->data;
            $n = "CWS" . substr($n, 3, 8) . gzcompress(substr($n, 8, strlen($n)));
            $file_size = strlen( $n ) -3;
        } else {
            $file_size = strlen( $this->data )-3;
        }
        return array($file_size, $real_size['num'], "compressed" => $file_size, "real" => $real_size['num']);
    }

    /**
    * Return the current background color
    * @return mixed array or error if invalid file format
    * @access public
    */
    function getBackgroundColor()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        if($this->getVersion() >= 8){
            $this->_seek(26);
        } else {
            $this->_seek(21);
        }
        return $this->_readData();
    }

    /**
    * Set the new background color
    * @param integer $r (0,255)
    * @param integer $g (0,255)
    * @param integer $b (0,255)
    * @access public
    */
    function setBackgroundColor($r=0, $g=0, $b=0)
    {
        if(!$this->is_valid()){
            return;
        }
        $color  = pack("C", $r);
        $color .= pack("C", $g);
        $color .= pack("C", $b);

        if($this->getVersion() >= 8){
            $data = substr($this->data, 0, 28);
            $data .= $color;
            $this->data = $data . substr($this->data, 31, strlen($this->data));
        } else {
            $data = substr($this->data, 0, 23);
            $data .= $color;
            $this->data = $data . substr($this->data, 26, strlen($this->data));
        }
    }

    /**
    * Save current swf as a new file
    * @param string $filename filename
    * @param boolean $overwrite overwrite existing file
    * @return boolean true if saved succesfully
    * @access public
    */
    function write($filename, $overwrite = 1)
    {
        if(!$this->is_valid()){
            return false;
        }
        if(is_writeable(dirname($filename))){
            if(is_file($filename)){
                if($overwrite == 0){
                    return false;
                }
            }
            $newdata = $this->setCompression($this->getCompression());
            $this->fileWrite ($filename, $newdata, $mode = "wb");
            return true;
        } else {
            return false;
        }
    }

    /**
    * reads the SWF header
    * @return mixed associative array or error on fault
    * @access private
    */
    function stat()
    {
        if(!$this->is_valid()){
            $this->raiseError("Invalid SWF head TAG found in " . $this->file, $php_errormsg);
			return;
        }
        $filetype = $this->getFileType();
        $version = $this->getVersion();
        $filelength = $this->filesize();
        $rect = $this->getMovieSize();
        $framerate = $this->getFrameRate();
        $framecount = $this->getFrameCount();
        $background = $this->getBackgroundColor();
        $protection = $this->getProtected();
        return array(
            "zlib-compression" => $this->getCompression(),
            "fileType" => $filetype,
            "version" => $version,
            "fileSize" => $filelength,
            "frameRate" => $framerate,
            "frameCount" => $framecount,
            "movieSize" => $rect,
            "background" => $background,
            "protected" => $protection,
        );
    }

    /**
    * read tag type, tag length
    * @return array
    * @access private
    */
    function _readTag()
    {
        $n = $this->_readshort();
        if($n == 0)
        {
            return false;
        }
        $tagn = $n>>6;
        $length = $n&0x3F;
        if($length == 0x3F)
        {
            $length = $this->_readlong();
        }
        return array($tagn,$length);
    }

    /**
    * read long
    * @access private
    */
    function _readlong(){
        $ret = unpack("Nnum", $this->_read(4));
        return $ret['num'];
    }

    /**
    * read data of next tag
    * @return array
    * @access private
    */
    function _readData()
    {
        $tag = $this->_readTag();
        $tagn = $tag[0];
        $length = $tag[1];
        if($tagn == 9)
        {
            $r = $this->_readbyte();
            $g = $this->_readbyte();
            $b = $this->_readbyte();
            $data = array($r,$g,$b, "hex" => sprintf("#%X%X%X", $r, $g, $b));
            return $data;
        } else if($tagn == 24)
        {
            if($this->_readbyte() == 0x00){
                $this->_readbyte();
                $this->password = $this->_readstring();
            } else {
                $this->password = 0;
            }
            return true;
        }
        return array();
    }

    /**
    * read a string
    * @return string
    * @access private
    */
    function _readstring()
    {
        $s = "";
        while(true){
            $ch = $this->_read(1);
            if($this->point > strlen($this->data)){
                break;
            }
            if($ch == "\x00"){
                break;
            }
            $s .= $ch;
        }
        return $s;
    }


    /**
    * read internal data file
    * @param integer $n number of byte to read
    * @return array
    * @access private
    */
    function _read($n)
    {
        $ret = substr($this->data, $this->point, $n);
        $this->point += $n;
        return $ret;
    }

    /**
    * move the internal pointer
    * @param integer $num
    * @access private
    */
    function _seek($num){
        if($num < 0){
            $num = 0;
        } else if($num > strlen($this->data)){
            $num = strlen($this->data);
        }
        $this->point = $num;
    }

    /**
    * read short
    * @return string
    * @access private
    */
    function _readshort(){
        $pack = unpack('vshort',$this->_read(2));
        return $pack['short'];
    }

    /**
    * read single byte
    * @return string
    * @access private
    */
    function _readByte(){
        $ret = unpack("Cbyte",$this->_read(1));
        return $ret['byte'];
    }
    /**
    * read a rect type
    * @return rect
    * @access private
    */
    function _readRect(){
        $this->_begin();
        $l = $this->_readbits(5);
        $xmin = $this->_readbits($l)/20;
        $xmax = $this->_readbits($l)/20;
        $ymin = $this->_readbits($l)/20;
        $ymax = $this->_readbits($l)/20;
        $rect = array(
            $xmax,
            $ymax,
            "width" => $xmax,
            "height" => $ymax
        );
        return $rect;
    }

    /**
    * read position internal to rect
    * @access private
    */
    function _incpos(){
        $this->position += 1;
        if($this->position>8){
            $this->position = 1;
            $this->current = $this->_readbyte();
        }
    }
    /**
    * read bites
    * @param integer $nbits number of bits to read
    * @return string
    * @access private
    */
    function _readbits($nbits){
        $n = 0;
        $r = 0;
        while($n < $nbits){
            $r = ($r<<1) + $this->_getbits($this->position);
            $this->_incpos();
            $n += 1;
        }
        return $r;
    }

    /**
    * getbits
    * @param integer $n
    * @return long
    * @access private
    */
    function _getbits($n){
        return ($this->current>>(8-$n))&1;
    }

    /**
    * begin reading of rect object
    * @access private
    */
    function _begin(){
        $this->current = $this->_readbyte();
        $this->position = 1;
    }
}
?>
 
actually i've got the example slightly wrong for the error handling.

try this instead
Code:
<?php
require_once "File/File_SWF.php";
$file = "any_file.swf";
$swf = &new File_SWF($file);

if($swf->isValid){
	$result = $swf->stat();
}

if ($swf->isError){
	die($swf->getErrorMessages());
} else {
	print_r($result);
}
?>
 

Ohlala ... it works! ahaha :)

THANKS SO MUCH!

OK, I'll play around with this much more understandable code, size it down and get rid of all the OOP stuff that bothers me so much.

At least I'll be sure it will work on PHP5 as well.

Merci Monsieur ;)
 
to be sure it works try it with a duff file too. the error handling is what has been changed the most.

you can easily make this a standalone suite of procedural code but i wouldn't bother. classes/objects come in handy for this kind of thing: encapsulation.

avec plaisir, quand même.
 
Since this is for a private CMS and that the files are bound to be working ones, only a file_exists() check will be applied.

Bonne nuit! :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top