Jump to content

Dynamic Sigs


W4RP3D
 Share

Recommended Posts

I would like to make a dynamic sig which shows my time on a game useing the xml of xfire *Clicky* Ive read into it and relise i would nead to write a program in php to collect the data and then display it as a picture (and refresh ever 10 mins or so).

Has anyone had any experience with this? or can you point me to a good turoial?[/url]

Link to comment
Share on other sites

Just wrote this example code for getting the amount of time played for each game and outputting it. It isn't brilliant, but it works ok.

<?php

$xml = file_get_contents ( 'http://xfireplus.com/xfireplus/xfirexml/xfire_xml.php?username=w4rp3d1' );

$xml = preg_replace ( '/>(n|r|rn| |t)*</','><', $xml ); //remove  unnecessary whitespace



$i = 0; //interator for games array

$games = array ( ); //array to store info about games

$element = ''; //current element

$gsection = false; //bool to store whether we are currently parsing the <games> section



function start_element ( $parser, $name, $attribute )

  {

    global $element, $gsection;

    

    $element = $name; //set current element



    if ( $name == 'games' ) //if we are entering the <games> section set $gsection to true

      {

        $gsection = true;

      }

  }



function end_element ( $parser, $name )

  {

    global $i, $gsection;

    

    if ( $name == 'game' && $gsection == true ) //increment iterator if we have just finished parsing a game and are in the <games> section

      {

        $i++;

      }



    if ( $name == 'games' )  //if we are exiting the <games> section set $gsection to false

      {

        $gsection = false;

      }

  }



function cdata ( $parser, $data )

  {

    global $element, $i, $games;

    

    if ( $element == 'gamename' ||

         $element == 'thisweek' ||

         $element == 'alltime' ) //if the current element is one of the three we need the cdata is for add it to the associative array

      {

        $games[$i][$element] = $data;

      }

  }



$parser = xml_parser_create ( );



xml_set_element_handler ( $parser, 'start_element', 'end_element' ); //set handler functions

xml_set_character_data_handler ( $parser, 'cdata' );



xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING, FALSE ); //don't pass element names in uppercase



xml_parse ( $parser, $xml ); //parse!



xml_parser_free ( $parser );



//can now do whatever with the array of associative arrays that we have

foreach ( $games as $game )

  {

    echo 'Game: ' . $game['gamename'] . '<br />';

    echo 'Time this week: ' . sprintf ( "%.1f", $game['thisweek'] / 3600 ) . ' hours<br />';

    echo 'Total time: ' . sprintf ( "%.1f", $game['alltime'] / 3600 ) . ' hours<br /><br />';

  }



?>

Link to comment
Share on other sites

You'd want something like this:

<?php

$xml = file_get_contents ( 'http://xfireplus.com/xfireplus/xfirexml/xfire_xml.php?username=w4rp3d1' );

$xml = preg_replace ( '/>(n|r|rn| |t)*</','><', $xml ); //remove unnecessary whitespace



$i = 0; //interator for games array

$games = array ( ); //array to store info about games

$element = ''; //current element

$gsection = false; //bool to store whether we are currently parsing the <games> section



function start_element ( $parser, $name, $attribute )

  {

    global $element, $gsection;

    

    $element = $name; //set current element



    if ( $name == 'games' ) //if we are entering the <games> section set $gsection to true

      {

        $gsection = true;

      }

  }



function end_element ( $parser, $name )

  {

    global $i, $gsection;

    

    if ( $name == 'game' && $gsection == true ) //increment iterator if we have just finished parsing a game and are in the <games> section

      {

        $i++;

      }



    if ( $name == 'games' )  //if we are exiting the <games> section set $gsection to false

      {

        $gsection = false;

      }

  }



function cdata ( $parser, $data )

  {

    global $element, $i, $games;

    

    if ( $element == 'gamename' ||

         $element == 'thisweek' ||

         $element == 'alltime' ) //if the current element is one of the three we need the cdata is for add it to the associative array

      {

        $games[$i][$element] = $data;

      }

  }



$parser = xml_parser_create ( );



xml_set_element_handler ( $parser, 'start_element', 'end_element' ); //set handler functions

xml_set_character_data_handler ( $parser, 'cdata' );



xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING, FALSE ); //don't pass element names in uppercase



xml_parse ( $parser, $xml ); //parse!



xml_parser_free ( $parser );



//can now do whatever with the array of associative arrays that we have



$height = 48 * count ( $games ) + 10;

$image = imagecreate ( 300, $height );

    

$grey = imagecolorallocate ( $image, 40, 40, 40 );

$black = imagecolorallocate ( $image, 0, 0, 0 );

$white = imagecolorallocate ( $image, 255, 255, 255 );



imagefilledrectangle ( $image, 0, 0, 299, $height, $grey );

imagesetthickness ( $image, 3 );

imagerectangle ( $image, 0, 1, 299, $height - 3, $black );



$ycursor = 5;



foreach ( $games as $game )

  {

    $gamename = 'Game: ' . $game['gamename'];

    $thisweek = 'Time this week: ' . sprintf ( "%.1f", $game['thisweek'] / 3600 ) . ' hours';

    $totaltime = 'Total time: ' . sprintf ( "%.1f", $game['alltime'] / 3600 ) . ' hours';



    imagestring ( $image, 4, 5, $ycursor, $gamename, $white );

    $ycursor += 16;

    imagestring ( $image, 4, 5, $ycursor, $thisweek, $white );

    $ycursor += 16;

    imagestring ( $image, 4, 5, $ycursor, $totaltime, $white );

    $ycursor += 16;

  }



header ( 'Content-type: image/png' );

imagepng ( $image );

?>

That's just a very basic example giving you this sort of thing:

xmlparse5iq.png

That just uses a built-in font of GD and 3 bits of info, obviously if you wanted to you could have little icons like on your current sig and more info from the XML file, and a nicer TrueType font. If you gave a bit more info of what exactly you are after I can give you more idea of how to accomplish it.

Link to comment
Share on other sites

Thank you, if its not too much problem could you run it through to me so i can see actually how it works and what does what.

Also when I try to run the last one this error apears,

Fatal error: Call to undefined function imagecreate() in C:Documents and SettingsWilliamDesktopSig.php on line 63

How do i fix this?

Link to comment
Share on other sites

That error smells like a missing GD library. Not a clue how you would install that beast under Windows though.

Update!

From the GD library FAQ:

php 4.3.x is available, and it includes a version of gd as "standard equipment." php_gd2.dll is included in a standard PHP installation for Windows, it's just not enabled by default. To turn it on, the user may simply uncomment the line "extension=php_gd2.dll" in php.ini and restart the PHP extension. Change:

#extension=php_gd2.dll

To:

extension=php_gd2.dll

You may also have to correct the extension directory setting from:

extension_dir = "./"

Or:

extension_dir = "./extensions"

To (FOR WINDOWS):

extension_dir = "c:/php/extensions" NOTE: SUBSTITUTE THE ACTUAL PHP INSTALLATION DIRECTORY ON *YOUR* COMPUTER.

Link to comment
Share on other sites

Thank you, if its not too much problem could you run it through to me so i can see actually how it works and what does what.

Sure, I'll go through section by section, not sure how much you already know so I'll try to explain quite simply.

<?php

$xml = file_get_contents ( 'http://xfireplus.com/xfireplus/xfirexml/xfire_xml.php?username=w4rp3d1' ); //

$xml = preg_replace ( '/>(n|r|rn| |t)*</','><', $xml ); //remove unnecessary whitespace



$i = 0; //index for $games

$games = array ( ); //array to store info about games

$element = ''; //current element

$gsection = false; //bool to store whether we are currently parsing the <games> section

This part first of all retrieves the XML as one long string and put it in $xml, and then removes any whitespace (i.e. newlines, tabs and spaces) which is between two tags if there is nothing else between them (without this I got stange behaviour). This is achieved using regular expressions, which is a sort of way of matching text to a pattern. You can read about those here.

We then declare and initialise some global variables which will be used to store information which which be required in more than one function. The reason for using global variables is normal (local) variables in a function only exist until the leaving the scope of the fujntion, we can use static variables to maintain the value and only have is accessible to the function it was delcared in, or used global variables which will mean it keeps its value and will be accessible to other functions. You can read more about variable scope here.

$i is used to store the index to use for the array storing the information about each game (it's not really an iterator, not sure why I put that previously) which is stored in $games, which is an array. Arrays (if you don't know) are used to store more than one element of data which is set and retrieved using an index or key, in this case we are using an array of arrays, known as a multidimensional array, you can read more about arrays here. $element is used to store the XML element we are currently on or in, you'll se more of how that is used further down. $gsection is used to indicate if we are in the <games> section (that is between <games> and </games>. This is because there is also <game> elements which aren't used to store information about play time futher down in the XML, which we don't care about.

function start_element ( $parser, $name, $attribute )

  {

    global $element, $gsection;

    

    $element = $name; //set current element



    if ( $name == 'games' ) //if we are entering the &lt;games&gt; section set $gsection to true

      {

        $gsection = true;

      }

  }

This is the function that xml_parse will call whenever it encounters a start element in the XML, e.g. <games>, <game>, <servers>, etc. It passes or gives the function the name of the element and its attributes (as an associative array, one that uses a string to identify its elements) to the function. So for instance if the element was <game id="game0"> in $name we would have "game" and in $attribute['id'] we would have "game0".

First, we declare $element and $gsection as global so we have access to those variables. We then set $element to the value of $name, so we can find out anywhere in the program what the last element we encountered was. We check if the element name is "games", if it is it means we have just encountered the <games> element so we set $gsection to true. Read more about control structures here

function end_element ( $parser, $name )

  {

    global $i, $gsection;

    

    if ( $name == 'game' &amp;&amp; $gsection == true ) //increment iterator if we have just finished parsing a game and are in the &lt;games&gt; section

      {

        $i++;

      }



    if ( $name == 'games' )  //if we are exiting the &lt;games&gt; section set $gsection to false

      {

        $gsection = false;

      }

  }

This is the function that xml_parse will call whenever it encounters a end element in the XML like </games> or </game>. It passes the name of the element but there are no attributes this time, because end elements don't have attributes.

Like before we declare our global variables, in this case $i and $gsection. Then we check if we have reached a </game> element and are within the <games> section. If both of those are true then that means we have just finished storing information about a games, and any new information we store will be about a different game, therefore we increase $i by 1, so when we store more stuff in $games it will be in a different element. Next we check in the end tag we have just reached is </games>, if it is we set $gsection to false because we have just left the section.

function cdata ( $parser, $data )

  {

    global $element, $i, $games;

    

    if ( $element == 'gamename' ||

         $element == 'thisweek' ||

         $element == 'alltime' ) //if the current element is one of the three we need the cdata is for add it to the associative array

      {

        $games[$i][$element] = $data;

      }

  }

This function is called when we reach some character data. Character data is text which is not part of an element, that is it is before, between and after elements. This includes whitespace, which is why we removed it earlier. For example in:

&lt;username&gt;w4rp3d1&lt;/username&gt;

&lt;status&gt;Online&lt;/status&gt;

&lt;nickname&gt;W4rp3d&lt;/nickname&gt;

&lt;avatar&gt;

http://media.xfire.com/xfire/xf/images/avatars/gallery/default/xfire.gif

&lt;/avatar&gt;

"w4rp3d1", "Online", "W4rp3d" and "http://media.xfire.com/xfire/xf/images/avatars/gallery/default/xfire.gif" are all charcter data. The function is passed the character data as a string.

We first (as in the last 2 functions) delcare the global variables we need. We then check if the $element variable is one of the three that contains the information we want, this is the reason we have a variable storing the last element. For example if $element is "nickname" it means we last encounters the element <nickname>, and any character data after that is (hopefully) going to be the nickname. If it is one of those three variables we set the element of the associative array with the key of th XML element name (which is in an element of $games itself) to the character data within it. So if we are on the second game encountered and the last XML element was "alltime" and the character data is "187200" then $games[1]['alltime'] will be set to "187200". The index is 1 for the second game because in PHP (and most other C-derived languages) array indices start at 0.

$parser = xml_parser_create ( );



xml_set_element_handler ( $parser, 'start_element', 'end_element' ); //set handler functions

xml_set_character_data_handler ( $parser, 'cdata' );



xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING, FALSE ); //don't pass element names in uppercase



xml_parse ( $parser, $xml ); //parse!



xml_parser_free ( $parser );

Here is when we do the actual parsing of the XML, first we create an XML parser which we will use to parse the XML and store its resource handle in $parser. We then set some options, specifically tell it the names of the handler functions to use (the ones we just created earlier) and tell it not to pass element names as upper case (since in PHP string comparisons are case sensitive). We could have just all the names in upper case and left this out, but there was no point in changing them. We then run the xml_parse function which is the function that actually does the parsing and then free the parser (basically destroys it ).

//can now do whatever with the array of associative arrays that we have



$height = 48 * count ( $games ) + 10;

$image = imagecreate ( 300, $height );

    

$grey = imagecolorallocate ( $image, 40, 40, 40 );

$black = imagecolorallocate ( $image, 0, 0, 0 );

$white = imagecolorallocate ( $image, 255, 255, 255 );



imagefilledrectangle ( $image, 0, 0, 299, $height, $grey );

imagesetthickness ( $image, 3 );

imagerectangle ( $image, 0, 1, 299, $height - 3, $black );



$ycursor = 5;

Here is where we start making the image. First we work out what height the image should be (based on how many games we have) and store it in $height. We then create the image itself with imagecreate, which we give the width and height of the image (You can read more about the image functions here). Next we set some colours which we will use later these are just some decimal RGB values. We then draw a filled rectangle which covers the entire image and is the grey we just created, this is just there as a background. We then set the thickness (in pixels) of any lines we draw, which is used an the thickness of the lines in the (non-filled) rectangle we draw. This is just a border and is black. $ycursor is set to 5, this is used an a placemarker for how far down the image (in pixels) we should be putting things.

foreach ( $games as $game )

  {

    $gamename = 'Game: ' . $game['gamename'];

    $thisweek = 'Time this week: ' . sprintf ( "%.1f", $game['thisweek'] / 3600 ) . ' hours';

    $totaltime = 'Total time: ' . sprintf ( "%.1f", $game['alltime'] / 3600 ) . ' hours';



    imagestring ( $image, 4, 5, $ycursor, $gamename, $white );

    $ycursor += 16;

    imagestring ( $image, 4, 5, $ycursor, $thisweek, $white );

    $ycursor += 16;

    imagestring ( $image, 4, 5, $ycursor, $totaltime, $white );

    $ycursor += 16;

  }

Here we cycle through each element of $games, which is put into $game. First we set the string we are going to write to the image, the sprintf is a way of formatting a string, in this case we set it to only show one decimal place (since when we divide by 3600 to get the times into hours we will probably get a very long number). We then put the string on the image, using font number 4 (there are 5 built-in fonts), 5 pixels across, howver many pixels down $ycursor has and in white. We then increase $ycursor by 16 (because in this font a line is 16 pixels high) and write out the next string. When we reach the end the loop will go on to the next game, or if this is the last or only element the loop ends.

header ( 'Content-type: image/png' );

imagepng ( $image );

?&gt;

We output the content type header (so the browser knows it is a PNG image) and then the PNG data itself.

I haven't proof-read this so there are almost certainly mistakes, but hopefully you will get what I mean and if you don't understand something I can try to explain better. There are also a lot of improvements that could be made to this (aside from the aesthetic ones) such as chaching the XML data so it doesn't take so long to load the image which we are waiting for it to got get it.

Fatal error: Call to undefined function imagecreate() in C:Documents and SettingsWilliamDesktopSig.php on line 63

How do i fix this?

Cooper has said how to fix this, although I'll just point out you don't specifically need PHP 4.3.x, anything after that should have the GD library as well.

Link to comment
Share on other sites

Woo Horza thanks that was a lot, i get some of it but not all. But now ive decided im going to try and learn some php seeing as ive got a few weeks off.

Im getting this error now after trying to fix the first error

Warning: Cannot modify header information - headers already sent by (output started at C:Documents and SettingsWilliamDesktopSig.php:1) in C:Documents and SettingsWilliamDesktopSig.php on line 89

‰PNG

Link to comment
Share on other sites

lol (kicks self) thanks its really good, youve done alot for me already but if you have time could you show me to add a jpeg or giff. So that it is a banner shape and the xfire stuff in in the bottom right hand corner. Thank you.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...