SystemWisdom 0 Report post Posted July 12, 2005 (edited) PHP Dynamic Signatures using the GD Module ????[/tab]After much scowering on the internet to find a suitable tutorial on this subject, I came up empty-handed. So I was forced to learn it on my own through trial & error. And since I had discovered a lack of tutorials on this subject, I dediced to write one! Working Example: Abstract: ????Using the GD Module of PHP allows a developer to build custom Images with Dynamic Content. Such content could be the Requesting Users IP Address, Web-Browser Type, Operating System, even the number of times the user has seen the Image! ????Luckily, Xisto Supports the GD Module with PHP, so those who are hosted here on Xisto can take full advantage of this tutorial! (Hint: Get Hosted With Xisto!) By Rob J. Secord, B.Sc. (SystemWisdom) Intended Audience: Intermediate to Advanced PHP Web-Application Designers/Developers. Assumed knowledge: -- PHP Basics/Arrays -- OOP Concepts such as Classes -- MySQL Databases with PHP -- MIME-Type Headers Theory: ????First, we will start with a simple Image Background that has some appeal (It is recommended that you create a simple Image Template in your favorite Image Editing software, like Photoshop) and remember to leave some space for the dynamic content to be added. ????After that, we simply access the image using PHPs GD Module, and write some dynamic content to it. We then output the image as a GIF file format and set the MIME-Type Content Headers to reflect a GIF image. ????To add to the images dynamic content, we will track the number of times an individual user requests the image, and store that into a MySQL Database. For this we will also require a database connection to MySQL. ????On to the fun stuff! NOTE: You can Download a complete ZIP file containing all files used in this tutorial as well as the suggested directory structure, at the end of this tutorial! Implementation: For this tutorial, I will use the following file structure (all files will be covered in this tutorial): -- .htaccess -- install.php -- sig_syswiz.php (NOTE: Will be renamed to sig_syswiz.gif later in tutorial) -- images ????|--- systemwisdom.gif -- fonts ????|--- arial.ttf -- dynasig ????|--- dynasig.inc.php The Bold entries are Folders, and the Italic entries are Files. Now, imagine those are the real file and folder names, as I will use those names in examples for the rest of this tutorial. ????We will start off by making (or selecting) an image to use as our Image Template, for this tutorial I will use the image below: Image File: images/systemwisdom.gif ????You should copy your image to your web-server using the same directory structure as listed above (you could place it anywhere you want really, just be sure your PHP code can access it). Now that you know what the Image Template looks like, you can look at my Example Signature to compare it to the finished result. ????Next we will use a True-Type Font for writing our Dynamic Content to the image. This gives us more flexibility with our fonts than what PHP provides for us. For this tutorial I am using a simple Arial Type font, and you can find this font in your Windows\Fonts directory (or on the Internet) or you could use any other True-Type Font that you want to use. ????The font file should be added to your web-server using the same directory structure as listed above (fonts/arial.ttf). ????Next we will get into the Bulk of the PHP code to achieve our Dynamic Signature. This code will be a Class called 'DynaSig' in the dynasig/dynasig.inc.php file and could be re-used for other signatures as well. Note: Although the DynaSig Class file would require minor modifications to work with other signatures (mainly text locations), it could easily be enhanced to be more dynamic requiring no changes at all to the DynaSig Class file. That is an exercise I will leave up to you! ????Now, I will begin by showing you the completed class file, and I will then explain each part of it as we go along in this tutorial. Note: Although this class will work, it only provides basic functionality and much could be added to it, but we will keep it simple for this tutorial. The DynaSig Class file would look like the following: DynaSig Class file: dynasig/dynasig.inc.php <?phpclass DynaSig{ // Dynamic Signature Version var $m_szVersion; // True-Type Font Styles var $m_szFontFace; var $m_aFontColor; var $m_iFontSize; // Image Template File var $m_szRawImage; // Dynamic Image Object var $m_oRawImage; // Quote/Author Arrays for Random Quote var $m_szQuotes; var $m_szAuthor; function DynaSig() { // Version $this->m_szVersion = 'v1.0'; // Default Font Styles $this->m_szFontFace = ''; $this->m_aFontColor = Array( 255, 255, 255 ); $this->m_iFontSize = 12; $this->m_szRawImage = ''; $this->m_oRawImage = 0; // Random Quotations $this->m_szQuotes = Array(); $this->m_szAuthor = Array(); } // // PUBLIC MEMBER FUNCTIONS BELOW... // function SetImageFile( $szFile ) { $this->m_szRawImage = 'images/' . $szFile . '.jpg'; } function SetFontFile( $szFile ) { $this->m_szFontFace = 'fonts/' . $szFile . '.ttf'; } function SetFontColor( $iRed, $iGreen, $iBlue ) { $this->m_aFontColor[0] = $iRed; $this->m_aFontColor[1] = $iGreen; $this->m_aFontColor[2] = $iBlue; } function SetFontSize( $iSize ) { $this->m_iFontSize = $iSize; } function AddQuote( $szQuote, $szAuthor ) { if( strlen( $szQuote ) && strlen( $szAuthor ) ) { $this->m_szQuotes[] = $szQuote; $this->m_szAuthor[] = '- ' . $szAuthor; } } function Create() { $this->m_oRawImage = imagecreatefromjpeg( $this->m_szRawImage ); imagealphablending( $this->m_oRawImage, true ); // Bounds of Map Image $iWidth = imagesx( $this->m_oRawImage ); $iHeight = imagesy( $this->m_oRawImage ); // Get User Data $szIP = $_SERVER['REMOTE_ADDR']; $szOS = $this->GetOperatingSystem(); $szBrowser = $this->GetBrowser(); // Get User View Count $iViewCount = $this->CountViews( $szIP, $szOS, $szBrowser ); // Write User Data to Image $this->WriteTTF( 10, 48, 'Hello '.$szIP.', You have viewed '.$iViewCount.' of my posts!' ); $this->WriteTTF( 10, 61, 'You are using '.$szBrowser.' on '.$szOS.'!' ); // Print Random Quote to Image $iIdx = rand( 0, count($this->m_szQuotes) - 1 ); $this->WriteTTF( 10, ($iHeight - 20), $this->m_szQuotes[$iIdx] ); $this->WriteTTF( 50, ($iHeight - 8), $this->m_szAuthor[$iIdx] ); // Output Image to Browser imagegif( $this->m_oRawImage ); // Free Image Resource imagedestroy( $this->m_oRawImage ); return; } // // PRIVATE MEMBER FUNCTIONS BELOW... // function CountViews( $szIP, $szOS, $szBrowser ) { // Connect to Database $iConnID = mysql_connect( 'localhost', 'my_username', 'my_password' ); mysql_select_db( 'my_database', $iConnID ); // Query Database for Matching User $szQuery = 'Select * From DynaSigData Where UserIP=\''.$szIP.'\' And UserOS=\''.$szOS.'\' And UserBrowser=\''.$szBrowser.'\''; $szQueryID = mysql_query( $szQuery, $iConnID ); $szResultSet = mysql_fetch_array( $szQueryID ); @mysql_free_result( $szQueryID ); if( !$szResultSet ) { // User not found, first viewing.. $szQuery = 'Insert Into DynaSigData (UserViews, UserIP, UserOS, UserBrowser ) '; $szQuery .= 'Values ( 1, \''.$szIP.'\', \''.$szOS.'\', \''.$szBrowser.'\' ) '; mysql_query( $szQuery, $iConnID ); $iViewCount = 1; }else { // User found, add 1 to view count.. $iUserID = intval( $szResultSet['UserID'] ); $iViewCount = intval( $szResultSet['UserViews'] ) + 1; $szQuery = 'Update DynaSigData Set UserViews='.$iViewCount.' Where UserID='.$iUserID.';'; mysql_query( $szQuery, $iConnID ); } // Disconnect DB @mysql_close( $iConnID ); // Return View Count return $iViewCount; } function WriteTTF( $iLocX, $iLocY, $szText ) { $oColor = imagecolorallocate( $this->m_oRawImage, $this->m_aFontColor[0], $this->m_aFontColor[1], $this->m_aFontColor[2] ); imagettftext( $this->m_oRawImage, $this->m_iFontSize, 0, $iLocX, $iLocY, $oColor, $this->m_szFontFace, $szText ); } function GetOperatingSystem() { // Operating System Types $aUserOS = Array( 'Windows XP' => 'Windows NT 5.1', 'Windows 2000' => 'Windows NT 5.0', 'Windows NT 4.0' => 'Windows NT 4', 'Windows 9x' => 'Windows 9', 'Windows 9x' => 'Win 9', 'Windows Me' => 'Windows Me', 'Linux' => 'Linux', 'Macintosh' => 'Macintosh' ); // Check for Matching Operating System foreach( $aUserOS as $szKey => $szValue ) if( preg_match( '/' . $szValue . '/i', $_SERVER['HTTP_USER_AGENT'] ) ) $szUserOS = $szKey; // If OS Not Found, Set Default Operating System if( !isset( $szUserOS ) ) $szUserOS = 'Some Weird OS'; // Return Operating System return $szUserOS; } function GetBrowser() { // Browser Types $aUserBrowser = Array( 'Internet Explorer 6' => 'MSIE 6', 'Internet Explorer 5' => 'MSIE 5', 'Internet Explorer 4' => 'MSIE 4', 'Firefox' => 'Firefox', 'Netscape 7' => 'Netscape7', 'Netscape 6' => 'Netscape6', 'Opera' => 'Opera' ); // Check for Matching Operating System foreach( $aUserBrowser as $szKey => $szValue ) if( preg_match( '/' . $szValue . '/i', $_SERVER['HTTP_USER_AGENT'] ) ) $szUserBrowser = $szKey; // If OS Not Found, Set Default Browser Type if( !isset( $szUserBrowser ) ) $szUserBrowser = 'Some Weird Browser'; // Return Browser Type return $szUserBrowser; } } // End of Class?> ????First of all, you will see a Class Declaration named 'DynaSig' and within it, are a bunch of Member Variables. They are all self-explanitory (though I will explain them eventually anyway), as is the Constructor which sets their respective default values. Now assuming you understand Object-Oriented Programming, I trust you understand thus far.????Moving on, you will notice 4 Set Functions which are used to setup the Format of the Dynamic Signature Image. These are used directly after Creating a DynaSig Object to set the Image Template file, the True-Type Font file, the Font Color and the Font Size respectively. You will notice that the SetImageFile() and SetFontFile() functions automatically add the directory and the extension to the parameter passed in. This is a personal preferrence which simply enforces the file location and type. You may also notice that we are using JPEG type images as our Image Template. This is important due to the nature of JPEG and GIF Images, as we will discuss later in this tutorial. ????Next is the AddQuote() function, which is the same as the Set functions from above, the only difference is that this function accepts 2 parameters (namely the Quote and Author) and adds their values to arrays. These arrays will be used to draw out a random quote later in this tutorial and write it to the Dynamic Signature Image. ????Now since those were all very basic functions, I will not explain them as thuroughly as I will the next 2: ????The Create() function, which is the last of our 'Public Functions' and the last one we will call when using our DynaSig Object, will output a Dynamic GIF Image to the requesting users browser. ????From here, the Create() function will call all of the other 'Private Functions' used in the class. But the first thing our Create() function must do, is open an Image Handle to the Image Template file we will be using. This handle is a Copy of the Image Template and we can then alter it without altering the original Image Template File. We open this image handle using the imagecreatefromjpeg() function from the GD Module in PHP. ????Now the reason why we open the Image Template as a JPEG is because GIF Images store their color indexes internally. If you open a GIF image of solid black, for example, you would not be able to add additional colors, since the GIF file only has a color index of Solid Black. Basically, the more colors in the GIF file then the more colors you can use with the GD module. Alternatively, JPEG files do not have this limitation, therefore it is more flexible to open your Image as a JPEG to get access to more colors. In the end however, we will still be outputting a GIF (generated dynamically) as they tend to be smaller in size. ????Once we have the Image Handle opened, we can then determine the Images Size using the imagesx() and imagesx() functions. This will give us the Width and Height of our image (this could be used for dynamically positioning text). ????After that, we determine the users IP Address using the built-in PHP Global Server Variable $_SERVER['REMOTE_ADDR'] which gives us a string containing the requesting users IP address! Brilliant! ????Then we can query the requesting users HTTP Agent string contained in yet another PHP Global Server Variable called $_SERVER['HTTP_USER_AGENT'] which contains both the Operating System and Browser details. We simply match the patterns using Regular Expressions against some known types, and if a specified pattern exists, we know the users HTTP Agent! This can be seen in the GetOperatingSystem() and GetBrowser() functions at the bottom of the Class File. Since both of these functions are relatively simplistic I will not explain them in great detail, though feel free to ask questions if any of it confuses you. ????Next we Query our Database to find the requesting users View Count, or in other words, how many times the user has accessed out signature image! This is done in the CountViews() function and I will describe it in greater detail later. For now, know that it returns an integer containing the requesting users View Count. ????After all of that is done, all of our Information Gathering is complete, so now we will need to write that information to the image. This is accomplished by the WriteTTF() function which first allocates the correct Color (as set by the SetFontColor() function) for use in the Image, and then writes the Information to the Image according to the Font Styles defined by the Set functions. The most important part of this function are the first 2 parameters which specify the X and Y locations of where to write the text to the Image. ????Next we will write our random quote to the Image. By adding quotes to our class using the AddQuote() function, we essentially build an array of Quotes. To choose one of them, we simply generate a random number between the Upper and Lower Bounds of the Array. This is accomplished with the PHP rand() and count() functions. With our random number we use it to index our array of quotes to write one of them to the Image. This process is pretty straight-forward. ????Finally, the last part of the Create() function is to output the image to the requesting users browser and then release the Image Handle from memory. This is accomplished by calling imagegif() and imagedestroy() respectively. One thing to note though, is that PHP will now output an Image instead of a Web-Page. Since our browser sent a request for a PHP page, it is expecting a Web-Page in return, not just an Image. We will have to modify the MIME-Type Headers to reflect the new content-type later on, before we use this class and call its associated Create() function. That will be done in our next file. ????After the Create() function we have the CountViews() function, which is the last function we will need to discuss in our DynaSig Class file. As mentioned earlier, this function is used to Query the Database for the requesting user to count the number of times they have viewed our Dynamic Signature Image. ????The first thing you'll notice, is that it connects to a Database. Your Access Credentials for Your DB MUST be supplied here (unless you change the code a bit). Next it searches the database for a user who matches the requesting users IP, OS and Browser. All 3 are used in the search to lessen the likely-hood of 2 users joining with the exact same data, and thus preventing user A to view user B's view count. If the user IS found in the database, then we simply store the users view count in an interger variable, add 1 to it, and then update the database with the new view count. Otherwise, if the user IS NOT found, then we set the users view count to 1 and insert a new record in the database for the current user. That pretty much sums up the CountViews() function, and gives us the current users view count. ????Now with that file done, and out of the way, you can place it on your web-server in the suggested directory mentioned at the beginning of this tutorial, and we will link to that file in the next file we discuss; the sig_syswiz.php file, which creates an object of our DynaSig Class, supplies the Image Template File and the Font Styles, and finally creates the image for output. You could have several of these files all pointing to different Image Templates, setting differnet Font Styles and still use the same DynaSig Class file. ????Again, I will first show you the completed file and then we will walk through it together: Main file: sig_syswiz.php <?php// Set Content Type to GIF with NoCacheheader( "Content-type: image/gif" );header('Expires: ' . gmdate('D, d M Y H:i:s') . 'GMT');header('Cache-control: no-cache');// Include DynaSig Class filerequire( 'dynasig/dynasig.inc.php' );// Create DynaSig Object$oDynaSig = new DynaSig();// Set Image Template File$oDynaSig->SetImageFile( 'systemwisdom' );// Set Font Styles$oDynaSig->SetFontFile( 'arial' );$oDynaSig->SetFontColor( 88, 100, 133 );$oDynaSig->SetFontSize( 10 );// Add Some Custom Quotes$oDynaSig->AddQuote( 'I have not failed, I have just found 10,000 ways that won\'t work!', 'Thomas Alva Edison' );$oDynaSig->AddQuote( 'Give me a museum and I\'ll fill it!', 'Pablo Picasso' );$oDynaSig->AddQuote( 'Where the spirit does not work with the hand, there is no art.', 'Leonardo da Vinci' );// Create and Output the Image$oDynaSig->Create();?> ????The first thing I hope you notice, is the size of this file -- it is much smaller than the DynaSig Class File! Yay!????Next, you will notice that the Content-Type is set to GIF. Remember, when accessing this file, you are accessing a PHP file which by default outputs HTML as the content type. Since we are actually outputting a GIF Image through this PHP code, we need to change the content-type before-hand. Also, the image is set to expire immediately forcing it to not be cached, and instead re-processed with each request. ????After that, we can begin creating our Dynamic Image! We first include our DynaSig Class file for use within this script, and instatiate an object of our DynaSig Class. Next we tell it the filename of our Image Template file, followed by the True-Type Font file and the respective Font Styles (Color/Size). Next we can add as many Custom Quotes as we want using the AddQuote() function created earlier, and finally, we Create and Output the Dynamic Signature Image by calling the Create() function! ????That's almost all there is to it! Our Dynamic Signature Image is nearly ready to be used! But we just have one more thing to do to make it work! We have to create the database, which is dont with the following PHP script: Install file: install.php <?php// Connect to DB$iConnID = mysql_connect( 'localhost', 'my_username', 'my_password' );mysql_select_db( 'my_database', $iConnID );// Check for Connection Errorif( !$iConnID ){ $szErrorMsg = 'Installer: Database Connection Failed!<br><br>Database Error Num: '; $szErrorMsg .= mysql_errno() . '<br>Database Error:<br>' . mysql_error(); die( $szErrorMsg );}// Drop Old Tablemysql_query( 'Drop Table `DynaSigData`;', $iConnID );// Create New Table$szQuery = 'Create Table If Not Exists DynaSigData (';$szQuery .= '`UserID` INT UNSIGNED DEFAULT \'1\' NOT NULL AUTO_INCREMENT PRIMARY KEY,';$szQuery .= '`UserViews` INT UNSIGNED DEFAULT \'0\' NOT NULL,';$szQuery .= '`UserIP` TEXT,';$szQuery .= '`UserOS` TEXT,';$szQuery .= '`UserBrowser` TEXT';$szQuery .= ') TYPE = MyISAM COMMENT = \'DynaSig Data\';';mysql_query( $szQuery, $iConnID );mysql_close( $iConnID );?> ????The install file requires little explanation, as it merely creates the Required Database table for tracking the user View Counts. Again, you MUST point this file to Your Database using Your Database Access Credentials. This file should only be run once before testing the Signature Image, and after it has been run and your database is installed, you can safely delete this file off of your web-server. ????Now we are done! (Or are we?) ????You could now access your Dynamic Signature by typing the address into you URL bar of your browser, and you will see the Dynamic Image (Ex: http://myDomain.com/sig_syswiz.php), but that will not work in a Forum for an Image Tag (), because most forums do not allow you to post images with an extension of .PHP (or any extension other than those used for online images, like gif, jpg, png or bmp). So in order to make this work for online forums, we will have to trick the forums by Renaming our sig_syswiz.php file to sig_syswiz.gif and then telling PHP to parse GIF files as PHP files in our DynaSig directory. This last step is as easy as renaming the above mentioned file, and adding the following .htaccess file to the same directory as the sig_syswiz.gif file: HT Access file: .htaccess ????Now you will be able to use your new Dynamic Signature in Online Forums! Yay! Putting it all together: ????If you now take all of the code samples from above and organize them according to the Suggested File Structure mentioned at the beginning of this tutorial, you will have a working Dynamic Signature for use in Forums and the like! Remember: You will still have to point to Your Database using Your Database Credentials in the DynaSig Class file as well as in the Install File which builds the appropriate Database Table! Working Example: "http://forums.xisto.com/no_longer_exists/404.png /> Conclusion: ????Well, I hope that you have learned something useful from this tutorial, and maybe even use such a Signature in online forums! ????Please feel free to comment on this tutorial, if you noticed anything wrong or out of place in this tutorial, please don't hesitate to mention it! [tab]I am interested in all feedback really, I'm curious about what you think of my writing, tutorial, methods used, code, effectiveness, layout, etc.. Thanks! Download Complete ZIP Package of Tutorial Edit: Added a download link Edited July 12, 2005 by snlildude87 (see edit history) Share this post Link to post Share on other sites
snlildude87 0 Report post Posted July 12, 2005 Excellent tutorial as always. :PI'll be sure to try this one since I have a server that supports PHP on hand - Xisto. Share this post Link to post Share on other sites
rvalkass 5 Report post Posted July 13, 2005 I had a go at making a dynamic sig before and couldn't find a secent, complete tutorial. Thanks very much. I will certainly try this when I have time! Share this post Link to post Share on other sites
sachavdk 0 Report post Posted July 14, 2005 Cool tutorial.I didn't know php could "see" which operating system a visitor uses.One other thing: do you have any idea on how to see the local IP of pc's behind a router or firewall? Share this post Link to post Share on other sites
badinfluence 0 Report post Posted July 17, 2005 excellent tutorial.... 10/10 rate it! Share this post Link to post Share on other sites
xenosaga 0 Report post Posted July 26, 2005 Cool ! But it's rather long for a small result for me. I think I will work on this tutor when I have a long holiday. Just kiddin'.Btw, maybe it will look nice on my sig.//I hope\\ Share this post Link to post Share on other sites
el_exorcista 0 Report post Posted August 1, 2005 Exellent lots of details (what is always great) I was starting to learn php but i had to stop as soon as i get a piece of space that support php and mysql ill start again and try this. Share this post Link to post Share on other sites
jhsmurray 0 Report post Posted June 18, 2006 That's a really handy tutorial there, Rob! btw, I originally got a "cannot open file or stream" error,so changed the image source file format from GIF to JPG in order to get it to work. Share this post Link to post Share on other sites
SolarX 0 Report post Posted June 18, 2006 Though I can't see your Working Examples it's an excellent tutorial. I alawys tought about implementing such dynamic images in my sites or the pictures linking to it, but I never had the time or tutorials to do it. Now that I've got a tutorial, I just need some time Share this post Link to post Share on other sites
kylelnsn 0 Report post Posted June 18, 2006 sorry yo say that i cannot see your working example and i cannot dowload your complete tutoral, seems as though your site is down or you have moved the files else where, would love to download and see the working example and give this one a little wizz to see if its any good!! great postother wise extremely informative and very detailed, if i get porblems i will post here and i look foward to seeing some more brilliant tutorials in the future from you hopefully, thanks so much for sharing and a great addition to the Xisto family and trap 17 community, thanks Share this post Link to post Share on other sites