PHP New Major Version

When you see a change in the major version (the number before the first point of the version id), expect a great leap. New features have been added to PHP in version 7, that make programming more convenient. I’m going to discuss some of them.

Null Coalescing

Suppose you’re trying to get a value from a request, and set it to zero if not sent. So instead of typing

$val = $_GET['foo'];
if ($val == null)
  $val=0;

Simply use ?? as follows:

$val = $_GET['foo'] ?? 0;

The Spaceship Comparison Operator

When making a decision based on comparisons between to values, would you like to use a switch command instead of if ... else? Use the operator ‘<=>’ to compare numbers or strings.
$a<=>$b will return one of the following values:
* -1 if $a is smaller than $b
* 0 if $a equals $b
* 1 if $a is greater than $b

Generator Functions

Generator functions have been introduced in PHP 5.5. They allow you to elegantly use generated values in a foreachloop without calling the function time and time again.
For example, the following code:

<?php
function factUpTo($n){
  $genValue=1;
  for ($i=1; $i<=$n;$i++){
    $genValue *= $i;
    yield $genValue;
  }
}

foreach (factUpTo(8) as $j){
  print $j . "\n";
}
?>

produces the following output:

1
2
6
24
120
720
5040
40320

Following are features introduced in PHP 7:

Returned Values

In addition to generating values, a generator can return a value using the return command. This value will be retrieved by the caller using the method getReturn().

For example, the code:


<?php

$gen = (function() {
    yield 1;
    yield 2;

    return 3;
})();

foreach ($gen as $val) {
    echo $val, PHP_EOL;
}

echo $gen->getReturn(), PHP_EOL;

will produce the output:

1
2
3

Delegation

A generator function can generate values using another generator function. This can be done by adding the keyword from after the command yield.
For example, the following code:


<?php
function gen()
{
    yield 1;
    yield 2;
    yield 4;
    yield from gen2();
}

function gen2()
{
    yield 8;
    yield 16;
}

foreach (gen() as $val)
{
    echo $val, PHP_EOL;
}
?>

will produce the following output

1
2
4
8
16

Return Type Declaration

A return type can be declare by adding it at the end of the function declaration after colons.
For example:

function myFunc(): int
{
.
.
.
return $retValue;
}

returns an integer.

Why Write The Return Type At The End?

Two possible reasons to write the type at the end of the declaration and not at the beginning like in Java, C, and other c-like languages:
* In PHP, the function declaration begins with the keyword funcction. The return type is optional.
* This syntax already exists in AcrionScript.

Find more about PHP 7 in the chapter Migrating from PHP 5.6.x to PHP 7.0.x of the php.net site documentation.

Written with StackEdit.

Advertisement

Browsing From The Command Line / Server With cURL

cURL is a tool used for browsing the web from the shell or command-line. It supports many internet protocols, such as HTTP, FTM, POP3, IMAP, SMTP and more. See the full list here.

With libcurl installed in your system and the C API, you can browse using a C program. You can also install the extension cURL for PHP.

Steps of a cURL Program

  1. Obtain a curl handle
    For example:

    $curl_handle = curl_init();
  2. Set options to the handle.
    Define the behavior of curl when executing the request: setting the URL, cookie location, variables passed to the server, etc.
    In PHP, you can use curl_setop to set a single option, or curl_setopt_array to pass a PHP array.
    For example:

    curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,true);

    will cause cURL to store the output in a string; the value ‘false’ will cause cURL to send it to the standard output.

  3. Execute the request.
    $out=curl_exec($curl_handle);
  4. Close the handle
    curl_close($curl_handle);

As long as the handle is open, you can repeat steps 2 and 3 as many times as you need.

Another useful cURL function is curl_getinfo. In the example below, I have used

"$httpCode = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);"

to determine if the login action was successful.

 An Example – Sharing a Message in LinkedIn

Publishing a text message in LinkedIn is simple: surf to LinkedIn, find the relevant form in the response and submit it. I’ve found the login form and the publish form using HTML Dom documents. Then populated post vars according to them, and connected to the URL given in the “action” attribute of the form. The code is run in PHP CLI in Linux (“stty -echo” is a system call that suppresses the echoing of input characters in Linux).

Step I – Surf to LinkedIn

In this step cURL will send a request to get the content in linkedin.com This is the first time, so the user is not logged in, and there are no cookies. The option CURLOPT_USERAGENT will make the server believe that the request has been sent from a real browser. The option CURLOPT_COOKIEJAR will define the file from which to store and retrieve cookies.

Following is the code:

<?php
error_reporting(E_ERROR | E_PARSE); //Suppress warnings

$curl_handle = curl_init();

// Connect to the site for the first time.
curl_setopt($curl_handle,CURLOPT_URL,"https://www.linkedin.com");
curl_setopt($curl_handle,CURLOPT_USERAGENT,'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:35.0) Gecko/20100101 Firefox/35.0');
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_handle,CURLOPT_COOKIEJAR,'/tmp/cookies');
$out = curl_exec($curl_handle);
if (!$out){
  echo "Error: " . curl_error($curl_handle) . "\n";
  die();
}

Step II – Get the Login Form, Populate It, and Submit It

In this step your script will read your e-mail address and password from the standard input (“php://stdin”), then populate the login form, and submit it. Using the Firefox extension DOM Inspector, I found that the Id of the form element is ‘login’, the username (e-mail) field’s name is “session_key”, and the password field’s name is “session_password”. The script willl submit the form with the input fields of type ‘hidden’ and with the entered e-mail and password. If the login was successful, the http code returned in the header would be 302, which means the output is returned from another address.

Following is the code:

$stdin = fopen('php://stdin','r');
echo "Enter e-mail:";
$email = trim(fgets($stdin));
system("stty -echo");
echo "Enter Password:";
$pass = trim(fgets($stdin));
system("stty echo");
echo "\n";
// Get the form inputs.
$doc = new DOMDocument();
$doc->loadHTML($out);

$form = $doc->getElementById('login');
$inputElements = $form->getElementsByTagName('input');
$length = $inputElements->length;

$inputs = Array();
for ($i=0;$i<$length;$i++){
  $elem=$inputElements->item($i);
  $name = $elem->getAttribute('name');
  $value = $elem->getAttribute('value');
  $inputs[$name]=$value;
}
$inputs['session_key']=$email;
$inputs['session_password']=$pass;
$keys = array_keys($inputs);
$postvars = '';

$firstInput=true;
foreach ($keys as $key){
  if (!$firstInput)
    $postvars .= '&';
  $firstInput = false;
  $postvars .= $key . "=" . urlencode($inputs[$key]);
}
$submitUrl = $form->getAttribute('action');

curl_setopt_array($curl_handle, Array(
  CURLOPT_URL=>$submitUrl,
  CURLOPT_POST=>true,
  CURLOPT_POSTFIELDS=>$postvars
));
$out=curl_exec($curl_handle);
$httpCode = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);

if ($httpCode != 302)
  die("Error - could not connect: $httpCode\n");

Step III – Post the Silly Message

After a successful login, the relevant data is stored in the cookie jar associated with the cURL handle. This time the script will read the content of the home page with the user logged in. A logged-in user can post status updates. This time, the operation is not complete until the “browser” is referred to the new address. So, we set the cURL option “CURLOPT_FOLLOWLOCATION” to true. In addition, PHP cURL allows to send an associative array as the value of the option “CURLOPT_POSTFIELDS”, a more elegant way to send POST data.

Following is the code:

// Post the message
curl_setopt($curl_handle, CURLOPT_URL, 'https://www.linkedin.com');
$out = curl_exec($curl_handle);
$doc = new DOMDocument();
$doc->loadHTML($out);
$form=$doc->getElementById('share-form');
$inputElements = $form->getElementsByTagName('input');
$length = $inputElements->length;
$inputs=Array();
for ($i=0;$i<$length;$i++){
  $elem=$inputElements->item($i);
  $name = $elem->getAttribute('name');
  $value = $elem->getAttribute('value');
  $inputs[$name]=$value;
}
$inputs['postText']="Hello! I am a message sent by a PHP script.";
$inputs['postVisibility2']='EVERYONE';
$keys=array_keys($inputs);


$formAction = $form->getAttribute('action');
if (substr($formAction,0,5)!='http:')
  $formAction = 'http://www.linkedin.com' . $formAction;

curl_setopt_array($curl_handle, Array(
  CURLOPT_URL=>$formAction,
  CURLOPT_POST=>true,
  CURLOPT_FOLLOWLOCATION=>true,
  CURLOPT_POSTFIELDS=>$inputs
));
$out = curl_exec($curl_handle);

curl_close($curl_handle);
?>

Creating Flash Sites With Ming

You probably know the SWF file format. This is not just a movie, but also can be an interactive application. SWF files can be created with the Ming PHP extension. You can get information on how to install and use the extension here. The movie format can be extended with a special scripting language, named ActionScript. Ming is not well-documented, so you can download a little API here, and maybe it will help you. There are also class for creating GUI objects, such as buttons, text fields, etc.

Let’s Discuss Some Classes

SWFMovie -The main class for movies, used for creating movies, and writing them to output streams.

Useful functions:

  • The constructor of course.
  • add – to add various objects, such as SWFAction scripts, sprites, shapes, buttons, text, etc.
  • save – to save your work to a file.
  • output – to send the output to the browser. before you send it, define the MIME type using
    header(‘Content-type: application/x-shockwave-flash’);

Notes:

  • Define the SWF version before you play it, or you will not be able to view the clip. Here‘s an user-contributed example of a way to determine the version and find more useful details. Set the version with ‘ming_useswfversion’.
  • Use scaling to avoid movies in strange sites at strange screen locations. We’ll discuss it later.
  • If you have created a movies from another movie, you must have access to the original movie from the new movie.

SWFAction – a class used for creating scripts. The scripts ca add functionality to the movie and make it interactive. It’s only function is the constructor, that takes scripts as its argument. You can use it for adding text fields – including input text fields -, communicate with other sites (using the LoadVars class for example), jumping to other frames, defining events, etc. Add it to your movie clips with the function ‘add’. Read more here.

an example of scaling with this class is:

  Stage.scaleMode='noScale';

Note: Error messages are not sent to the log, if they are not syntax errors.

SWFShape – used for creating shapes. This can be used for defining the shape of buttons (need not be rectangular). It can also be added to movie clips. With this class you can draw lines, arcs, and quadratic and cubic Bezzier curves.  You can fill your shape with colors, gradients or bitmaps. If your fill is an image, you can create an object of class SWFFill using “addFill ( SWFBitmap $bitmap [, int $flags ] ).”.  Then you can fill your shape using ‘setRightFill’ or ‘setLeftFill passing your fill as the argument.

SWFFill – This class does not have a constructor. An instance of this class is created by the function addFill of class  SWFShape . It is important to move the fill to the exact location using the function ‘moveTo’ and to scale it using ‘scaleTo”. If you want to use an image at its original dimension, you will probably have to scale it to (20,20) $fill->scaleTo(20,20) because the number of horizontal and vertical twips in a pixel is 20. In addition the fill can be rotated and/or skewed.

SWFButton – A button is a GUI element that triggers an action when clicked. You can add actions, sounds and shapes using the function addAction/setAction, addSound and addShape respectively. You better add a shape, to define the shape and location of the button. The prototype of addShape is ‘void addShape ( SWFShape $shape , int $flags )’. The flags are a combination (using bitwise or) of SWFBUTTON_UP, SWFBUTTON_OVER, SWFBUTTON_DOWN and SWFBUTTON_HIT. These flags define when the button is displayed.

An Example

This is an example of a script that plays a movie backwards:

$x = new SWFMovie();
.
.
.

$actionText = <<<'EOT'

this.createEmptyMovieClip("mc",2);

mc.loadMovie("selfie.swf", "GET");
this.gotoAndStop(mc._totalframes - 1);
this.createTextField("myText", this.getNextHighestDepth(), 0, 0, 200,220);
var tf:TextFormat = new TextFormat();
tf.color = 0x0;
tf.size = 30;
tf.font = "Arial";
myText.setTextFormat(tf);
this.addChild(myText);

this.onEnterFrame=function(){
  if (mc._currentFrame <= 1){
    mc.gotoAndPlay(mc._totalframes - 1);
  }
  mc.prevFrame();
}; 

EOT;
$act=new SWFAction($actionText);
//$x->add($text);
$x->add($act);


Sending Drupal Mail From Your GoDaddy Server

I have an account on Godaddy.com. This site allows its user to install products such as Drupal. Drupal is a 3rd-party PHP framework that can be installed automatically by web hosting sites. Sites built with Drupal can have registered users, and when a users signs up, they get confirmation e-mails. But the site does not send out e-mails yet. It should be configured1 specifying the e-mail address at ‘Home » Administration » Configuration » System’ is NOT enough. The PHP function ‘mail’ works properly, but if you try to find where drupal uses that function, it does not. Drupal invokes the system shell command ‘sendmail’ instead.

Searching what else I should do I found, that there is a module named SMTP, that can be downloaded from here.

Time to configure the SMTP module. I try to find the value for the field ‘SMTP Server’, but the value found in the E-Mail Setup Center was not helpful.

So, I tried to ask the Godaddy Support Team how the heck to configure SMTP, and got the following response

:Dear Amit,

Thank you for contacting Online Support in regards to Drupal.

Unfortunately we are unable to provide direct troubleshooting or support for 3rd party applications such as Drupal. I would suggest that you consult your favorite search engine for further assistance.

So, I tried to find a solution using Google. It was not very easy, but, eventually, I found that the server name is “relay-hosting.secureserver.net”. the port is 25, and no encryption protocol should be in use. The username and password should remain empy.

This is an old issue, I found it here, and I believe that the support team should come up with better responses than they sent me.

 

PHP CLI – Command Line Interface

If you have installed PHP, you probably have the PHP CLI as well. CLI allows you to run PHP scripts from the command line, without a browser or the definition of a virtual site. You can use it to define a Cron Job or a scheduled task, without learning PERL or other scripting languages. In linux, all you have to do is to put the following first line in your file:

  #!/usr/bin/php

or

  #!/usr/bin/env  php

if the path to ‘php’ is ‘/usr/bin/php’ or the path to ‘env’ is ‘/usr/bin/env’.

You should make your PHP script executable as well.

Superglobals are still defined, but this time are empty hashes, i.e. $_GET[“anyname”] will hold the value null.

 

Animated GIF Manipulating With GD

I had a task: to write a program that makes text from animated ‘gif’ images of letters. For example, the following image:

hw

Usually, the PHP extension ‘GD’ is good enough to perform the job. GD is an image processing extension, that allows a developer to create canvasses, place images of common formats in there, save your picture to an image file of your favorite format or to a string, and other operations. This time, GD generated the big image, but without the animation. But GD is still useful if you learn about the structure of a GIF  file, and you can get all the relevant information in this text file.

The Structure of a GIF File Made Simpler

A GIF File consists of the following:

  • File Header, begins with ‘GIF’ followed by ’87a’ or ’89a’ and 7 more bytes.
  • There may be a global color map, depending on byte 10. It’s size is calculated according to the 3 rightmost bytes of byte 10.
  • Extensions that begin with a byte of value 21h (“\x21”), including graphic control (“\x21\xf9”), text (“\x21\x01”), app data(“\x21\xff”), and comments (“\x21\xfe”).
  • Image Separator (“\x2c”).
  • A file Terminator (‘|x3b”).

The file can be processed by reading the header and using a state machine as follows:

  // Read the header
  $gif_string = my_fread($fd, 13);
  // Get the packed field;
  $value = ord(substr($gif_string, 10, 1));

  $globalMapExists = $value & 0x80;
  if ($globalMapExists){
    $tmp=($value & 0x07) + 1;
    $globalMapSize = 3 * (1 << $tmp);
  }  else
    $globalMapSize = 0;

  // Read Global Color Map
  if ($globalMapExists){
    $globalColorMap = my_fread($fd, $globalMapSize );
    $gif_string .= $globalColorMap;
  }

  // Data begins here.
  // Data blocks begin with:
  //   0x2C - Image Descriptor
  //   0x21 - Extensions: Graphic Control, Comment, Text, Application.
  $curr_frame = -1;
  $gc_encountered = FALSE;
  while (($chr = my_fread($fd, 1)) != "\x3B"){
    switch (ord($chr)){
      case 0x21:
        $next_chr = my_fread($fd, 1);
        switch (ord($next_chr)){
          case 0xf9:
            $curr_frame++;
            $frames[] = $gif_string . chr(0x21) . chr(0xf9) .
               read_frame($fd, $curr_frame);
            $gc_encountered = TRUE;
            break;
          case 0x01:
            if (!$gc_encountered){
               $frames[0] = $gif_string;
               $curr_frame = 0;
            }
            $frames[$curr_frame] .= chr(0x21) . chr(0x01) . read_text($fd);
            break;
          case 0xff:
            $gif_string .= chr(0x21) . chr(0xff) . read_app_data($fd);
            break;
          case 0xfe:
            $gif_string .= chr(0x21) . chr(0xfe) . read_comment($fd);
            break;

        }
        break;
      case 0x2c:
            if (!$gc_encountered){
               $frames[0] = $gif_string;
               $curr_frame = 0;
               $gc_encountered=TRUE;
            }
            $frames[$curr_frame] .= chr(0x2c) . read_image($fd, $curr_frame);
            break;    }
  }

Doing it With GD

The steps of the program are as follows:

  1. Create an image resource for each letter using the function $res=imagecreatefromgif($url).
  2. Get the width and height of each letter using imagesx($res) and imagesy($res). Use these values to find the size of the output image.
  3. Split each image into frames using the state machine.
  4. Create the output frames using ‘imagecreate($total_width, $total_height);’Note: the image created by GD is not stored in GIF format.
  5. If the frame is new set its transparent background using the following commands:
    1. $tci = imagecolortransparent($frame_res);  // Get the transparent color index from the original frams.
    2. imagepalettecopy($out_frames[$curr_frame_no],$frame_res); // Copy the palette to the output frame.
    3. imagefill($out_frames[$curr_frame_no], 0, 0, $tci);  // Fill the output frame with the transparent color
    4. imagecolortransparent($out_frames[$curr_frame_no], $tci);  // Set the output frame’s transparent color.
  6. Place each letter’s frame in the output frame using the command:
     imagecopymerge($out_frames[$curr_frame_no], // Destination image      $frame_res, // Source image      $pos_in_pic + $left_positions[$curr_frame_no], // Destination x,      $top_positions[$curr_frame_no], // Destination y,       0, //$left_positions[$curr_frame_no], // Source x,      0, //$top_positions[$curr_frame_no], // source y,     $width,     $height,100);
  7. Now, use a state machine similar to the one described above to create the output GIF file.

Communication Between Backbone.js And PHP

Backbone.js is a Javascript framework known as MV* (Model, View and stuff). This framework has the Backbone.sync function to perform CRUD (Create, Read, Update, Delete) operations. In order for a model object to perform these operations, it should have a property named ‘url’. The ‘sync’ function receives 3 arguments: method, model and options. Model objects also have functions that call the ‘sync’ functions, these functions are: ‘fetch’, ‘save’ and ‘destroy’. The function Save does both Create and Update operation: If the property idAttribute is defined, and the idAttribute is set, ‘save’ sends an update request, otherwise it sends a ‘create’ request. The content type of the request is ”application/json”.

How Does The Server Know What Request Type It Receives?

The client-side developer specifies one ‘url’ only per model. The server-side program can determine the type by checking the value of $_SERVER[‘REQUEST_MOTHED’]:

  • ‘GET’ – a read (or fetch) request.
  • ‘POST’ – a create(save a new model) request.
  • ‘PUT’ – an update(save existing model’s detail) request.
  • ‘DELETE’ – a delete(destroy) request.

What To Send and How To Read?

Backbone.sync uses AJAX to send requests to the server. What you have to pass is the method and model. You better not skip the 3rd arguments, options, which contains at least two member:

  • ‘success’ – a function called when the server processes the request successfully.
  • ‘error’ – a function called when the server fails to process the request.

For example:

Backbone.sync(‘GET’, myModel, {

success: function(resp){

// process the response

},

error: function(resp){

// Recover or print an error message.

}

});

If you call Backbone.sync from an object don’t use ‘this” inside the success and error function as a reference to your object.

For example, if you call ‘sync’ from a view, write ‘myView=this;’ before your call to the ‘sync’ function.

Read Requests

If you send a ‘fetch’ request, specify ‘data’ in the ‘options’ argument, for example:

myModel.fetch({

data: {‘attr1′:’value1’, ‘attr2′:’value2’, … , ‘attrN’:”valueN’},

success:

….

error:

});

In the Server Side

The request attributes are taken from $_GET or $_REQUEST, as usual.

Save Requests

Send the attributes and the options.

For example:

myModel.save(myModel.attributes, {

success:

error:

….

});

In The Server Side

The data should be read from the file “php://input”, a filename used for reading data from the request body. The content is a string, and should be parsed, but since the incoming request data is JSON encoded, you should use the PHP method “json_decode”.

For example:

$post_vars = json_decode(file_get_contents(‘php://input’), true);

Destroy Requests

This time, you should set the ‘data’ member of the options argument to a JSON string. For example:

Backbone.sync(‘delete’, myModel,{
data: JSON.stringify(myModel),  // This time the developer encodes the data.

success: function(model, resp) {

…..

},

error: function(){

….

} );

In The Server Side

Read the data from ‘php://input’ and decode it using json_decode. For example:

$post_vars = json_decode(file_get_contents(‘php://input’), true);

Anyways …

You can make sure you read the data correctly by sending the contents of ‘$_SERVER’, $post_vars and ‘$_REQUEST’ to the error_log. To print an array use json_encode.

Sending a Response To the Client

The response is everything the server side application prints to the standard output. You should print your response data encoded into JSON, as follows:

echo json_encode(responsedata);

Reading a Response

The response returned from the server is the first argument passed to the ‘succss’ callback function. It is not a model object, and you should get values from there using the method ‘get(attr-name’ or the member ‘attributes’.

For example:

{success: function(msg){
switch (msg.get(‘status’)){  // Get the value of the attribute ‘status’ in the server’s response.

To debug your code, you can use ‘alert(JSON.stringify(msg));’.

JSON, The New XML

When you write for the web, you may want to send data to another server or to a client. A common way to transfer that data is in XML format. The data will then be processed using SAX, DOM or XPath. Every language support it.

If what you want is to define a variable, an object or an array in Javascript, you can use the JSON extension. JSON is an acronym for ‘Java Script Object Notation’. In Javascript you can use it as follows:

var myObject=<?php echo json_encode($php_object); >;

Here no parsers are required.

Here’s an example of using it in PHP:

<?
class my_class {
  public $prop1;
  public $prop2;

  function __construct(){
    $this->prop1='a';
    $this->prop2=400;
  }
}

$obj=new my_class();
echo json_encode($obj);
?>

The output looks like:
{“prop1″:”a”,”prop2″:400}

In addition to encoding, a JSON string can be decoded into an object in a language other than Javascript. Thus, you can pass data in the JSON format to any program supporting JSON, and, as you can see in www.json.org, most languages used today support it.

The ability to encode varibles into JSON and decode it back in any language is not the only reason why JSON can replace XML. If you go to www.json.org, you can see links in the bottom referring to other sites. For example, JSONPath, that allows you to access a member just like XPath. JSONPath is available in PHP and Javascript.

ImageMagick Workaround for SVG Support

I have installed the PECL package IMagick in my computer. Its current version 7:6.6.2.6 -1 does a great job converting SVG files into raster images. In my hosting account the Imagemagick package is not the most recent: I have an SVG file that contained elemants repeated using the Inkscape’s spray can, but when I convert it using a test program in my host it only print one of the repeated stars.

How can I resolve this?

Well, as you probably know, SVG is an XML format, so I can read it using a text editor. Doing this I found that there’s an element named ‘use’ with an attribute named ‘href’. “href” we know from HTML, and the element’s named “use” makes sense when using an existing element. So I commented out all the “use” elements, and viewing the SVG file as an image I saw the star at the exact location as in the  erroneous raster image, but with other elements not printed there. Probably the SAX engine stopped after the first unknown element. Commented out all elements from the first “use” elements until the end of file, and BINGO! This reproduced the problem. Well, the “use” elements should be replaced by the original ones with changes to their attributes. The following code does it:

/**
* I found that the "use" tags are not supported, so I'm replacing them
* by something else.
*
* The function returns the content of the file, the returned value can be the 1st argument of 
* Imagick::readImageBlob
*/
function svg_workaround($filename){
  $mimeType = mime_content_type($filename);

  if ($mimeType != 'text/xml' && mimeType!='image/svg+xml'){
  // At home the mime type is "Image/svg+xml" in the hosting account "text/xml"
    return file_get_contents($filename);
  }

  $contents = file_get_contents($filename);
  $docRoot = new DOMDocument(); // For random access and fast location of referenced objects
                                                     // you would use 'DOM'.

  if (!$docRoot->loadXML($contents))
    return FALSE;

  $xlinkNs = getXLinkNs($docRoot); // For the "href" attribute.

  $svgElems = $docRoot->getElementsByTagName('svg');
  if (!$svgElems->length)
    return $contents;

  $nodeList = $docRoot->getElementsByTagName('use');

  // Because the node lists changes when elements are replaces, we keep the elements in an array.
  $nodes = array();
  for ($i=0; $ilength; $i++)
    $nodes[]=$nodeList->item($i);

  foreach ($nodes as $node)
    if (!replace_use_tag($node, $docRoot, $xlinkNs))
      return false;

  return $docRoot->saveXML();
}

// The function that replaces the "use" elements
function replace_use_tag($node, $doc, $xlinkNs){
  $href=$node->getAttribute($xlinkNs . ':href');
  if (!$href)
    $href=$node->getAttribute('href');

  if (!$href)
    return FALSE;

  $id=substr($href, 1); // Removing the '#' from the href.
  if (!$id)
    return FALSE;
  // We use 'xpath' to locate a node with a given id because, unlike HTML, the use of getElementById
  // in XML DOM is not trivial.
  $xpath=new DOMXPath($doc);
  $elems=$xpath->query('//*[@id=\'' . $id . '\']');
  $orig=$elems->item(0);

  if (!$orig)
    return FALSE;

  $newNode=$orig->cloneNode(TRUE); // TRUE for deep cloning; When cloning a composite such as "g",
                                                             // its child elements should be copied as well.

  // Copy attributes from the 'use' node to the new node, not including the 'href'
  $attributes=$node->attributes;

  $length=$attributes->length;

  for ($i=0; $iitem($i); $i++){
    $attrName=$item->name;
    $attrValue=$item->value;
    if ($attrName=='href' || $attrName==$xlinkNs . ':href')
      continue;
    $newNode->setAttribute($attrName, $attrValue);
  }

  $parent=$node->parentNode;
  $parent->replaceChild($newNode, $node);
  return TRUE;
}

// Get the namespace for XLink.
function getXLinkNs($doc){
  return $doc->lookupPrefix('http://www.w3.org/1999/xlink');
}

Extending PHP

Extending PHP does not mean just adding classes and functions. It also means adding functionality not previously supported by PHP. This can be done by writing functions in C that can be called from PHP. These functions should be able to receive parameters passed from PHP. The difference between a variable in a C source and a variable in PHP is that in PHP the variable in PHP is loosely typed. That is, in PHP a variable can be used as an integer, but later as a string or a floating point number, so its equivalent in C is zVal. “zval” is a structure containing the variable’s type and a union made up of members of different types sharing the same memory address.

The PHP extension is a dynamically linked library (‘dll’ in Windows, ‘so’ in Linux) containing functions that can be called from PHP.

The process of creating an extension is described in the chapter “PHP at the Core: A Hacker’s Guide to the Zend Engine” in the famous PHP manual.

Building the extension starts with tunning the ‘ext_skel’ script, which creates a directory for your extension including a skeleton of the extension’s C code and a header file.

The next step is to add functions and global variables using macros.

The macro used for defining a  function is PHP_FUNCTION(function_name). Returning a value is done using the macros RETURN_TRUE, RETURN_FALSE, RETVAL_* . These macros are in /path/to/php_include_dir/Zend/zend_API.h

Arguments are passed to local C variables using the function ‘zend_parse_parameters’.

The next step is to edit config.w4(Linux) or config.w32(windows), then run ‘phpize’ and ‘configure’ to create a Makefile.

Finally, run make.

The dynamically loaded library will be created in the ‘modules’ directory. Use ‘make install’ with root permissions to copy your extension to the PHP extension directory.

Unfortunately, the guide is far from being complete, so to look for examples, browse ‘pecl.php.net‘ for source codes.