19 May 2010

Watermark Images with Text Using PHP and GD Library

Hi

This code snippet allows you to watermark uploaded images on the fly. The script saves the uploaded image in the specified location, the prints the specified message (for example a copyright notice) on the image and saves the watermarked image as a JPEG file in another location. You can use this script to copy-protect your images by permanently imprinting a copyright notice on the image. Though the example script covers most general needs, PHP programmers should customize the script for their needs.

The Complete Example

The working code sample consists of the following items:
  • HTML form that posts an image to the PHP script
  • The PHP Script

HTML Form
The HTML form needs a file upload element :<input type="file">. You must also specify the correct encoding type: enctype="multipart/form-data" for the form.

<form action="watermark-image.php" method="post" enctype="multipart/form-data">
 Select a file to upload for processing<br>
 <input type="file" name="File1"><br>
 <input type="submit" value="Submit File">
</form>

The PHP Script


<?php
 //----------------------------------------------------------------
 // render_text_on_gd_image
 // THE FUNCTION THAT ACTUALLY RENDERS THE STRING
 //----------------------------------------------------------------

 define( 'WATERMARK_MARGIN_ADJUST', 5 );
 define( 'WATERMARK_FONT_REALPATH', 'c:\\windows\\fonts\\' );

 function render_text_on_gd_image( &$source_gd_image, $text, $font, $size, $color, $opacity, $rotation, $align )
 {
  $source_width = imagesx( $source_gd_image );
  $source_height = imagesy( $source_gd_image );

  $bb = imagettfbbox_fixed( $size, $rotation, $font, $text );

  $x0 = min( $bb[ 0 ], $bb[ 2 ], $bb[ 4 ], $bb[ 6 ] ) - WATERMARK_MARGIN_ADJUST;
  $x1 = max( $bb[ 0 ], $bb[ 2 ], $bb[ 4 ], $bb[ 6 ] ) + WATERMARK_MARGIN_ADJUST;
  $y0 = min( $bb[ 1 ], $bb[ 3 ], $bb[ 5 ], $bb[ 7 ] ) - WATERMARK_MARGIN_ADJUST;
  $y1 = max( $bb[ 1 ], $bb[ 3 ], $bb[ 5 ], $bb[ 7 ] ) + WATERMARK_MARGIN_ADJUST;

  $bb_width = abs( $x1 - $x0 );
  $bb_height = abs( $y1 - $y0 );

  switch ( $align )
  {
   case 11:
    $bpy = -$y0;
    $bpx = -$x0;
    break;
   case 12:
    $bpy = -$y0;
    $bpx = $source_width / 2 - $bb_width / 2 - $x0;
    break;
   case 13:
    $bpy = -$y0;
    $bpx = $source_width - $x1;
    break;
   case 21:
    $bpy = $source_height / 2 - $bb_height / 2 - $y0;
    $bpx = -$x0;
    break;
   case 22:
    $bpy = $source_height / 2 - $bb_height / 2 - $y0;
    $bpx = $source_width / 2 - $bb_width / 2 - $x0;
    break;
   case 23:
    $bpy = $source_height / 2 - $bb_height / 2 - $y0;
    $bpx = $source_width - $x1;
    break;
   case 31:
    $bpy = $source_height - $y1;
    $bpx = -$x0;
    break;
   case 32:
    $bpy = $source_height - $y1;
    $bpx = $source_width / 2 - $bb_width / 2 - $x0;
    break;
   case 33;
    $bpy = $source_height - $y1;
    $bpx = $source_width - $x1;
    break;
  }

  $alpha_color = imagecolorallocatealpha(
   $source_gd_image,
   hexdec( substr( $color, 0, 2 ) ),
   hexdec( substr( $color, 2, 2 ) ),
   hexdec( substr( $color, 4, 2 ) ),
   127 * ( 100 - $opacity ) / 100
  );

  return imagettftext( $source_gd_image, $size, $rotation, $bpx, $bpy, $alpha_color, WATERMARK_FONT_REALPATH . $font, $text );
 }

 //----------------------------------------------------------------
 // imagettfbbox_fixed
 // FIX FOR THE BUGGY IMAGETTFBBOX IMPLEMENTATION IN GD LIBRARY
 //----------------------------------------------------------------

 function imagettfbbox_fixed( $size, $rotation, $font, $text )
 {
  $bb = imagettfbbox( $size, 0, WATERMARK_FONT_REALPATH . $font, $text );
  $aa = deg2rad( $rotation );
  $cc = cos( $aa );
  $ss = sin( $aa );
  $rr = array( );
  for( $i = 0; $i < 7; $i += 2 )
  {
   $rr[ $i + 0 ] = round( $bb[ $i + 0 ] * $cc + $bb[ $i + 1 ] * $ss );
   $rr[ $i + 1 ] = round( $bb[ $i + 1 ] * $cc - $bb[ $i + 0 ] * $ss );
  }
  return $rr;
 }

 //----------------------------------------------------------------
 // CREATE WATERMARK FUNCTION
 //----------------------------------------------------------------

 define( 'WATERMARK_OUTPUT_QUALITY', 90 );

 function create_watermark_from_string( $source_file_path, $output_file_path, $text, $font, $size, $color, $opacity, $rotation, $align )
 {
  list( $source_width, $source_height, $source_type ) = getimagesize( $source_file_path );

  if ( $source_type === NULL )
  {
   return false;
  }

  switch ( $source_type )
  {
   case IMAGETYPE_GIF:
    $source_gd_image = imagecreatefromgif( $source_file_path );
    break;
   case IMAGETYPE_JPEG:
    $source_gd_image = imagecreatefromjpeg( $source_file_path );
    break;
   case IMAGETYPE_PNG:
    $source_gd_image = imagecreatefrompng( $source_file_path );
    break;
   default:
    return false;
  }

  render_text_on_gd_image( $source_gd_image, $text, $font, $size, $color, $opacity, $rotation, $align );

  imagejpeg( $source_gd_image, $output_file_path, WATERMARK_OUTPUT_QUALITY );
  imagedestroy( $source_gd_image );
 }

 //----------------------------------------------------------------
 // FILE PROCESSING FUNCTION
 //----------------------------------------------------------------

 define( 'UPLOADED_IMAGE_DESTINATION', 'originals/' );
 define( 'PROCESSED_IMAGE_DESTINATION', 'images/' );

 function process_image_upload( $Field )
 {
  $temp_file_path = $_FILES[ $Field ][ 'tmp_name' ];
  $temp_file_name = $_FILES[ $Field ][ 'name' ];
  
  list( , , $temp_type ) = getimagesize( $temp_file_path );
  
  if ( $temp_type === NULL )
  {
   return false;
  }
  
  switch ( $temp_type )
  {
   case IMAGETYPE_GIF:
    break;
   case IMAGETYPE_JPEG:
    break;
   case IMAGETYPE_PNG:
    break;
   default:
    return false;
  }
  
  $uploaded_file_path = UPLOADED_IMAGE_DESTINATION . $temp_file_name;
  $processed_file_path = PROCESSED_IMAGE_DESTINATION . preg_replace( '/\\.[^\\.]+$/', '.jpg', $temp_file_name );
  
  move_uploaded_file( $temp_file_path, $uploaded_file_path );

  //----------------------------------------------------------------
  // PARAMETER DESCRIPTION
  // (1) SOURCE FILE PATH
  // (2) OUTPUT FILE PATH
  // (3) THE TEXT TO RENDER
  // (4) FONT NAME -- MUST BE A *FILE* NAME
  // (5) FONT SIZE IN POINTS
  // (6) FONT COLOR AS A HEX STRING
  // (7) OPACITY -- 0 TO 100
  // (8) TEXT ANGLE -- 0 TO 360
  // (9) TEXT ALIGNMENT CODE -- POSSIBLE VALUES ARE 11, 12, 13, 21, 22, 23, 31, 32, 33
  //----------------------------------------------------------------

  $result = create_watermark_from_string(
   $uploaded_file_path,
   $processed_file_path,
   'Copyrights (c) 2010',
   'arial.ttf',
   14,
   'CCCCCC',
   75,
   0,
   32
  );
  
  if ( $result === false )
  {
   return false;
  }
  else
  {
   return array( $uploaded_file_path, $processed_file_path );
  }
 }

 //----------------------------------------------------------------
 // END OF FUNCTIONS
 //----------------------------------------------------------------

 $result = process_image_upload( 'File1' );

 if ( $result === false )
 {
  echo '<br>An error occurred during file processing.';
 }
 else
 {
  echo '<br>Original image saved as <a href="' . $result[ 0 ] . '" target="_blank">' . $result[ 0 ] . '</a>';
  echo '<br>Watermarked image saved as <a href="' . $result[ 1 ] . '" target="_blank">' . $result[ 1 ] . '</a>';
 }
?>

How it Works

The example is divided into many functions. But there is only one that needs explanation:
render_text_on_gd_image
Important: Before using this function, modify the constant WATERMARK_FONT_REALPATH to point to a directory that contains fonts in TTF format. On Windows platform, this is usually the C:\Windows\Fonts\ directory. It is also possible to use TTF fonts from other locations, or you can copy required fonts with the script.
The primary function used in this example is the imagettftext function. The function renders the given text into the image using true-type fonts. The important parameters of this function include:
  • font size -- usually specified in "points"
  • text rotation -- specified in degrees
  • color -- may or may not contain transparency
  • a valid true-type font file path/name
While this looks easy, it becomes very complicated when you need rotated text. Adding to the complication, the function accepts the (x, y) coordinates of the text's basepoint and baseline, not the absolute lower left corner of the bounding box of the text.
The function therefore has to calculate the bounding box of the text that needs to be rendered, taking the angle into consideration. A modified version of the imagettfbbox does exactly that.
Note: This function was extracted from user contributed notes in the PHP manual.
Next, the placement of the bounding box on the source image is calculated and immediately the coordinates are converted to the x and y values that the imagettfbbox expects.
Finally, the imagettfbbox function is called to render the text on the source image.

Picture before water marking......................................

.

 Picture after water marking...........................................



You can play around with the parameters to the function render_text_on_gd_image to get different variations of watermarks. In particular, this example allows you to generate watermarks with various combinations of alignment, color, opacity, angle, font and font size.






16 May 2010

What is LAMP


What is LAMP?
LAMP includes a stack of software, mostly open source and free software, used to run dynamic websites or/and servers.

What is the advantage of LAMP and why should we use LAMP?
LAMP involves a combination of open source programs. LAMP allows for lower cost development and when the programs are used together they support application servers and development environments such as Java/J2EE and Microsoft.Net.
The combination in LAMP has become popular because of its low acquisition cost and because of the versatility of its components since it can be used in most of the Linux distributions.

The acronym of LAMP is as follows
  • Linux - operating system.
  • Apache - web server.
  • MySQL - Database management system or database server.
  • PHP or Perl, Python - programming languages.
Primarily, LAMP is a combination of the above-mentioned technologies which is used for a wide variety of purposes such to design a web server infrastructure, design a programming paradigm of developing software, and to establish a software distribution package.

14 May 2010

update content every X seconds using ajax

how to update some web page section or a block content on a page every x seconds. Some real life examples of this functionality are Twitter search results that come out when there are new tweets with search keyword or bit.ly real time link tracking that updates it’s charts every 5 seconds.

t is clear without saying that we are going to update our page content using AJAX and of course we love AJAX in jQuery flavor. So key to this functionality is JavaScript's built-in setInterval() function. It lets you to run some javascript function every X seconds. For example, the following code would pop alert box every five seconds:

setInterval( "alert('Hello')", 5000 );

Now consider we want to update shouts in our shoutbox every 10 seconds.

function updateShouts(){



// Assuming we have #shoutbox


$('#shoutbox').load('latestShouts.php');


}
setInterval( "updateShouts()", 10000 );

The code above will run every 10 seconds (10,000 ms) and update the contents of #shotbox with new shouts.

12 May 2010

Ajax Frameworks

The best technology to build dynamic web pages is Ajax. JavaScript code embedded into the HTML page is used to send requests to the server. At the server side, some processing is required to handle them, find the info or store the data. To do that, we need for a specialized framework. The framework has always a JavaScript part, and sometimes a server side part in another scripting language. A lot of them exist in various programming languages, in all environments around, but we retain here only the most widely used.
Summary
  • Why a framework?
  • JavaScript libraries
  • PHP frameworks
  • Java frameworks
  • .NET frameworks
  • ColdFusion frameworks
  • Ajax and XUL
  • Resources

Why a framework?

Actually, this framework is the Ajax engine described by J. J. Garrett and intended to suppress waiting for the user when accessing the server.

The framework provides classical, cross-browser functions to use the XMLHttpRequest object. But a framework may goes beyond that, and allow to build "rich web applications", applications with a graphical user interface and other features of desktop software that run through a browser, while exchanging data with a remote server.

JavaScript libraries

Many Ajax frameworks and libraries rely solely upon JavaScript and contain no server components and therefore server technology dependencies.

Most of them use XML as data format, and sometime JSON, another textual format.

A JavaScript library is loaded with just a tag, as this:
<script src="prototype.js" type="text/javascript></script>
This tag includes the "prototype" library into the page and its
function become usable by the browser, in this page.

Such Ajax libraries and frameworks include:
  • Prototype.

    Is the base of several other frameworks including that of Yahoo. Its goal seems to be in reducing the size of Ajax Code.
  • Script Aculo.

    Add more features to prototype.
  • Rico.

    Based also on prototype, add special effects to HTML pages.
  • Dojo Toolkit.

    Uses packages with a mechanism to load them together along with the page. It can build reusable components and widgets, a lot of them is provided on the site. It allows to manipulate the DOM more easily, and to make graphical effects.
  • Qooxdoo.

    Includes advanced cross-browser layout managers and an advanced build system for graphical user interfaces similar to that of desktop software. Widgets re provided with the function to use them from the keyboard or the mouse. Third parties provide PHP or Java code to process data with XMLHttpRequest.
  • Sarissa.

    ECMAScript library to process native XML APIs. Allow DOM instances, XML loading, XSLT transformations, XPath queries, serialization of lists into
    XML...
  • Yahoo UI.

    Library from the Yahoo search engine. Includes CSS resources.
  • Anaa.

    A simple library for GET and POST with callbacks.

PHP frameworks

On the server side, the programmer may use PHP functions to process requests from the browser. PHP allows to deal with database, search data, build pages or parts of page and publish the page or return data to the XMLHttpRequest
object. PHP 5 specifically, thanks to its SimpleXML class, is able to create XML files that may be returned to the object. But all these tasks require special functions to write... however the work is already done in some free open source frameworks.
  • AjaxAC.

    Small PHP library.
  • Xajax.

    More sophisticated, is made of a JavaScript library and PHP classes, to help in using other PHP functions written by you. Uses only the XML format, on the server side.
  • Tiny Ajax.

    A small PHP 5 class.

Java frameworks

Java is the programming language that is the more often used to build web services.

A Java framework permit to use Java web services interactively with a web page.

The more commonly used are:
  • DWR (Direct Web Remoting).

    Allows to use Java functions as if they are part of the browser, from HTML code, thanks to its interface. A JavaScript part is used to update the page and another to get data with servlets.

    The technique is in generating in real time Java code from JavaScript code, send it to the server and run it.
  • GoogleWeb Toolkit.

    A toolbox to develop Java applications, that are then compiled into JavaScript code, and this code processes the HTML page through DOM methods.
Legacy Java software for the web now is moving to Ajax. JavaServer Facesnow includes Ajax features. ThinWire takes a unique approach in that the application is written as if it was a desktop software. All the logic executes on the server, the framework encapsulates the web rendering and communication layers.

.NET frameworks

  • Microsoft Ajax Library (formerly ATLAS) is made of a client side part: Microsoft AJAX Library, and a server side part: ASP.NET 2.0 Ajax Extensions. But a component library is also provided with graphical widgets: ASP.NET Ajax Control Toolkit.
  • Ajax.NET Professional "serialize" (convert and store) .NET data to the JSON format.

ColdFusion frameworks

Libraries include:
  • AjaxCFC.
    An object oriented framework that provides developers seamless integration between JavaScript and ColdFusion, and built-in security and debugging functions.
  • CFAjax.
    Implements Ajax in such a way that ColdFusion method calls on the server gets executed using JavaScript a la Ajax.
  • JSMX. JSMX API
    runs entirely on the client and has no Server Side Components to install. Apart ColdFusion, is extended to support also XML, JSON, and WDDX or even JavaScript on the server side from JavaScript requests on the client side.

Ajax and XUL

Ajax make use of the JavaScript programming language, and XUL embeds also JavaScript into XML to define the interaction with the graphical user interface. The two systems work on the Firefox browser. The first one allows to communicate with the server from a remote web page, the second one displays an interface either in a local computer or through the net, with the same browser.

The main difference is in the use of Canvas (HTML tag) to extend Ajax and to extend XUL, XPCom and XBL.
  • ZK.

    Framework designed for allowing Ajax and XUL to communicate.

Resources

Article from http://www.xul.fr/ajax-frameworks.html


09 May 2010

what is new in php6

PHP 6.0 looks to be an exciting release. Nothing is absolutely fixed yet, but it looks like it will see the demise of three of my pet peeves: register_globals, magic_quotes_gpc and safe_mode. The first was just a big security hole, the second messed with the data and made changing environments potentially nightmarish, while the third was a misnomer that nobody really understood, and provided a false sense of security. There's also quite a lot of work scheduled to do with Unicode. Here are some of the changes:

  • The register_globals, safe_mode and the various magic quotes options will be removed.
  • The ereg extension is removed, while the XMLReader, XMLWriter and Fileinfo extensions are added to the core, and by default are on.
  • Another addition I find particularly exciting is that APC (Alternative PHP Cache) will be added to the core, though will be off by default. APC can provide serious performance benefits.
  • All E_STRICT messages will be merged into E_ALL, another positive change that will encourage good programming practice.
  • ASP style <% tags will no longer be supported.
  • Addition of a new 64-bit integers. The current integer type remains as is, 32 or 64-bit dependent on the platform.
  • Use of foreach with multi-dimensional arrays, for example foreach($array as $k => list($a, $b)).
  • A new switch in php.ini will allow you to disable Unicode semantics (by default they will be on).
  • There will also be various string improvements related to Unicode.
  • The microtime() function will return the full floating point number, rather than microseconds unix_timestamp, as at present, probably making the function more readily useful for most people.
  • The {} notation for string indexes will no longer be supported, while the [] version will get added substr() and array_slice() functionality. Previously [] was deprecated, but most developers, including myself, seem to use [].
  • FastCGI will always be enabled for the CGI SAPI, and will not be able to be disabled.
  • The ancient HTTP_*_VARS globals will no longer be supported. Everyone should have had more than enough time to remove any traces of these.
  • var will alias publicvar was permitted with PHP4 classes, but in PHP 5 this raised a warning. In PHP 6 var will simply be an alias for public, so no warning is necessary.
  • The ze1 compatibility mode, which tried to retain PHP 4 behaviour but had some bugs, will be removed.
  • Dynamic functions will no longer be permitted to be called with static syntax.

PHP Engine Additions

64 bit integers
A new 64 bit integer will be added (int64). There will be no int32 (it is assumed unless you specify int64)
Goto
No 'goto' command will be added, but the break keyword will be extended with a static label - so you could do 'break foo' and it'll jump to the label foo: in your code.
ifsetor()
It looks like we won't be seeing this one, which is a shame. But instead the ?: operator will have the 'middle parameter' requirement dropped, which means you'd be able to do something like this: "$foo = $_GET['foo'] ?: 42;" (i.e. if foo is true, $foo will equal 42). This should save some code, but I personally don't think it is as 'readable' as ifsetor would have been.
foreach multi-dim arrays
This is a nice change - you'll be able to foreach through array lists, i.e. "foreach( $a as $k => list($a, $b))".
{} vs []
You can currently use both {} and [] to access string indexes. But the {} notation will raise an E_STRICT in PHP5.1 and will be gone totally in PHP6. Also the [] version will gain substr and array_slice functionality directly - so you could do "[2,]" to access characters 2 to the end, etc. Very handy.

OO changes

Static Binding
A new keyword will be created to allow for late static binding - static::static2(), this will perform runtime evaluation of statics.
Namespaces
It looks like this one is still undecided - if they do implement namespaces it will be using their style only. My advice? Don't hold your breath!
Type-hinted Return Values
Although they decided against allowing type-hinted properties (becaue it's "not the PHP way") they will add support for type-hinted return values, but have yet to decide on a syntax for this. Even so, it will be a nice addition.
Calling dynamic functions as static will E_FATAL
At the moment you can call both static and dynamic methods, whether they are static or not. Calling a dynamic function with the static call syntax will raise an E_FATAL.


Additions to PHP

APC to be in the core distribution
The opcode cache APC will be included in the core distribution of PHP as standard, it will not however be turned on by default (but having it there saves the compilation of yet another thing on your server, and web hosts are more likely to allow it to be enabled)
Hardened PHP patch
This patch implements a bunch of extra security checks in PHP. They went over it and the following changes will now take place within PHP: Protection against HTTP Response Splitting will be included. allow_url_fopen will be split into two: allow_url_fopen and allow_url_include. allow_url_fopen will be enabled by default. allow_url_include will be disabled by default.
E_STRICT merges into E_ALL
Wow, this is quite a serious one! E_STRICT level messages will be added to E_ALL by default. This shows a marked move by the PHP team to educate developers on 'best practises' and displaying language-level warnings in a "Hey, you're doing it the wrong way".
Farewell <%
They will remove support for the ASP style tags, but the PHP short-code tag will remain (<?) - so to those on php general who reckon the short-tag is 'depreceated' - hah! ;)



08 May 2010

Tracking file upload progress in php

Tracking file upload progress

To receive a file, we must first set up a form which will receive the file. Conveniently, HTML comes with a standard field type for files. Like all HTML form fields, it is named logically, as type file It comes with a handy Browse button that appears to the right of the block by default.

HTML form for upload.php
<?php
$id = $_GET['id'];
?>

<form enctype="multipart/form-data" id="upload_form"
action="target.php" method="POST">

<input type="hidden" name="APC_UPLOAD_PROGRESS"
id="progress_key" value="<?php echo $id?>"/>

<input type="file" id="test_file" name="test_file"/><br/>

<input onclick="window.parent.startProgress(); return true;"
type="submit" value="Upload!"/>

</form>

We need to make a PHP page for this form because we need a unique key to track the upload. Ultimately, it will be part of the URL used to call this page as a GET value. This number is going to be the value for the APC cache entry key we will retrieve later. To pass that value, the form field needs a hidden field with a special name that will let APC know that it needs to store the file upload status. This field is called APC_UPLOAD_PROGRESS. This is the aforementioned hook that starts the caching process. To make sure PHP can access the correct item in the cache, we use the unique ID we retrieved as the value of the hidden field, thus creating a key of that value. Once the user submits the form -- we'll deal with the submit button shortly -- the browser sends the file and the key as part of the POST data sent to the server.


Catching the throw
When the file is included in the submitted form, it is sent to a temporary location on the server until it is saved to a permanent location. When it is in the temporary storage, it is available through the $_FILES  associative array. Using the file upload functions that are standard issue with PHP, you can select a path and save them to the server or handle them however you want.
The target.php file
<?php  

if($_SERVER['REQUEST_METHOD']=='POST') {
  move_uploaded_file($_FILES["test_file"]["tmp_name"], 
  "c:\\sw\\wamp\\www\\" . $_FILES["test_file"]["name"]);
  echo "
File uploaded.  Thank you!
";

}

?>


The getprogress.php file

Making progress



<?php
if(isset($_GET['progress_key'])) {


  $status = apc_fetch('upload_'.$_GET['progress_key']);
  echo $status['current']/$status['total']*100;


}
?>






              
JavaScript shows the bar
Now you just need a way to get the script to update the width not with an arbitrary number but with the completion percentage.

The main file, progress.php
Now you're ready to start building the actual progress bar. To keep things simple, the script uses CSS to create a div that emulates a bar and can be controlled using JavaScript,
              
<html>
<head><title>Upload Example</title></head>
<body>

<script type="text/javascript">

var counter = 0;

function startProgress(){
    document.getElementById("progressouter").style.display="block";
    fire();
}

function fire(){
   if (counter < 101){
     document.getElementById("progressinner").style.width =
                                                     counter+"%";
     counter++;
     setTimeout("fire()",100);
   }
}

</script>

<div id="progressouter" style=
    "width: 500px; height: 20px; border: 6px solid red; display:none;">
   <div id="progressinner" style=
       "position: relative; height: 20px; background-color: purple; width: 0%; ">
   </div>
</div>

<span onclick="startProgress()">Start me up!</span>

</body>
</html>


The final progress.php page

Putting it all together
All you've got left to do now is to hook everything together.



<?php
$id = uniqid("");
?>
<html>
<head><title>Upload Example</title></head>
<body>

<script src="http://maps.google.com/maps?file=api&v=2&key=<yourkeyhere>"
type="text/javascript"></script>

<script type="text/javascript">

function getProgress(){
GDownloadUrl("getprogress.php?progress_key=<?php echo($id)?>",
function(percent, responseCode) {
document.getElementById("progressinner").style.width = percent+"%";
if (percent < 100){
setTimeout("getProgress()", 100);
}
});

}

function startProgress(){
document.getElementById("progressouter").style.display="block";
setTimeout("getProgress()", 1000);
}

</script>

<iframe id="theframe" name="theframe"
src="upload.php?id=<?php echo($id) ?>"
style="border: none; height: 100px; width: 400px;" >
</iframe>
<br/><br/>

<div id="progressouter" style=
"width: 500px; height: 20px; border: 6px solid red; display:none;">
<div id="progressinner" style=
"position: relative; height: 20px; background-color: purple; width: 0%; ">
</div>
</div>

</body>
</html>

Starting at the bottom and working our way up, we've added an iframe that embeds the upload.php script,  feeding it the unique ID generated at the top of the page.


Now, remember the Submit button from that form?

That button does two things. It does submit the form, like a normal Submit button, but before it does that, it calls the startProgress() script in the main window. The startProgress() script tells the progress bar to display itself — it starts out with a display property of none —, then tells the browser to wait for one second before executing the getProgress() script.