Monday 22 September 2014

How to convert Objects to Arrays or Arrays to Objects in multi-dimensional arrays and objects ?

Dealing with the consumption de SOAP webservices, I have been encountered some trouble when extracting data with a mix of multidimensional arrays and objects ; a way to simplefy this extraction was to transform objects into array or arrays into objects using a recursive method:

Here below, one will find two recursive functions to convert multi-dimensional Objects To Array and Multidimensional Aarrays to Objects :

Function to Convert stdClass Objects to Multidimensional Arrays:

    function objectToArray($d) {
        if (is_object($d)) {
            // Gets the properties of the given object
            // with get_object_vars function
            $d = get_object_vars($d);
        }
 
        if (is_array($d)) {
            /*
            * Return array converted to object
            * Using __FUNCTION__ (Magic constant)
            * for recursive call
            */
            return array_map(__FUNCTION__, $d);
        }
        else {
            // Return array
            return $d;
        }
    }

Function to Convert Multidimensional Arrays to stdClass Objects:

    function arrayToObject($d) {
        if (is_array($d)) {
            /*
            * Return array converted to object
            * Using __FUNCTION__ (Magic constant)
            * for recursive call
            */
            return (object) array_map(__FUNCTION__, $d);
        }
        else {
            // Return object
            return $d;
        }
    }

Example:
<?php
      // Create new stdClass Object
      $init = new stdClass;
      $init->debut = "14:00";
      $init->fin = "18:00";

      $init2 = array();
      $init2[0]= new stdClass;
      $init2[0]->debut = "09:00";
      $init2[0]->fin = "12:00";
      $init2[1]= new stdClass;
      $init2[1]->debut = "14:00";
      $init2[1]->fin = "19:00";

      var_dump($init);
      var_dump($init2);
     // Convert objects to array and then array to  backobject
      $array = $this->objectToArray($init);
      $array2 = $this->objectToArray($init2);
      var_dump($array);
      var_dump($array2);
      $object = $this->arrayToObject($array);
      $object2 = $this->arrayToObject($array2);
var_dump($array2); function objectToArray($d) { if (is_object($d)) { // Gets the properties of the given object // with get_object_vars function $d = get_object_vars($d); } if (is_array($d)) { /* * Return object converted to array
            * Using __FUNCTION__ (Magic constant)
            * for recursive call
            */
            return array_map(__FUNCTION__, $d);
        }
        else {
            // Return array
            return $d;
        }
    }
    
    
    function arrayToObject($d) {
        if (is_array($d)) {
            /*
            * Return array converted to object
            * Using __FUNCTION__ (Magic constant)
            * for recursive call
            */
            return (object) array_map(__FUNCTION__, $d);
        }
        else {
            // Return object
            return $d;
        }
    }
?>

cf. http://www.if-not-true-then-false.com/2009/php-tip-convert-stdclass-object-to-multidimensional-array-and-convert-multidimensional-array-to-stdclass-object/


Using array_map within a class function is not straight forward : the reference to the function has to be written like this : array_map(array($this,__FUNCTION__), $d);

Here is an example of this usage :

<?php

    $Chrono = new Relais();
    $Chrono->convert();

    class Relais {

        public function convert()
        {
            // Create new stdClass Object
            $init = new stdClass;
            $init->debut = "14:00";
            $init->fin = "18:00";

            $init2 = array();
            $init2[0]= new stdClass;
            $init2[0]->debut = "09:00";
            $init2[0]->fin = "12:00";
            $init2[1]= new stdClass;
            $init2[1]->debut = "14:00";
            $init2[1]->fin = "19:00";

           // var_dump($init);
            //var_dump($init2);
            // Convert array to object and then object back to array
            $array = $this->objectToArray($init);
            $array2 = $this->objectToArray($init2);
            var_dump($array);
            var_dump($array2);
            $object = $this->arrayToObject($array);
            $object2 = $this->arrayToObject($array2);
           // var_dump($object);
            var_dump($object2);
        }
        private function objectToArray($d) {
            if (is_object($d)) {
                // Gets the properties of the given object
                // with get_object_vars function
                $d = get_object_vars($d);
            }

            if (is_array($d)) {
                /*
                * Return object converted to array 
                * Using __FUNCTION__ (Magic constant)
                * for recursive call
                */
                return array_map(array($this,__FUNCTION__), $d);
            }
            else {
                // Return array
                return $d;
            }
        }             

        private function arrayToObject($d) {
            if (is_array($d)) {
                /*
                * Return array converted to object
                * Using __FUNCTION__ (Magic constant)
                * for recursive call
                */
                return (object) array_map(array($this,__FUNCTION__), $d);
            }
            else {
                // Return object
                return $d;
            }
        }
    }
    

?>




Monday 15 September 2014

How to consume a REST/JSON webservice ?

In this post, I will give a way to consume a RESTFUL webservice, using the example given in the previous post for the webservice to be consumed :


 <?php

    $arg = '2';
    $function = 'double';
  
    //$function = 'doubleds';

    $base_url = 'http://localhost:8080/creation_service_rest.php';
    $query_string = '';
  
    $params = array (
        'function' => $function,
        'arg' => $arg,
    );
    //http://localhost/wp_phped/eros/eros/creation_service_rest.php?function=double&arg=2
  
    $query_string = get_urlrequest($params);

    $url = $base_url . "?" . $query_string;

  // $json =  file_get_contents($url);
   $content = URLToContent($url);

   $tab = json_decode($content, true);

 
   if (!empty($tab['response']['value'])) echo "Le double de $arg est ".$tab['response']['value'];
   else
   {
       if (!empty($tab['error']['code']))echo 'ERREUR : code '. $tab['error']['code'].' - '. utf8_decode($tab['error']['message']);
   }
 
 
    function URLToContent($url)
    {
        // create curl resource
        $curl = curl_init($url);

        curl_setopt($curl, CURLOPT_FAILONERROR, true);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $result = curl_exec($curl);

        //close curl resource to free up system resources
        curl_close($curl);  
        return $result;
    }

    function get_urlrequest($params) {
        $query_string = '';
        foreach ($params as $key => $value) {
            $query_string .= "$key=" . urlencode($value) . "&";
        }
        $query_string = substr($query_string,0,strlen($query_string) - 1);
      
        return $query_string;
      
     
    }
?>

This example is partly based on the one shown in  http://notos.fr/blog/index.php?article23/exemple-de-web-services-en-php

One could use instead the following functions to replace URLToContent and get_urlrequest functions, respectively:

function curl_get($url) {
      $client = curl_init($url);
      curl_setopt($client, CURLOPT_RETURNTRANSFER, true);
     $response = curl_exec($client);
     curl_close($client);
     return $response;
}


function build_query_string(array $params) {
       $query_string = http_build_query($params);
       return $query_string;
}


The next step will be to include both functions in one include ( for example : RestFulWS.php ):

One Example with consuming an RSS feed from BBC news : 

 <?php
require_once 'RestFulWS.php';
$url = 'http://feeds.bbci.co.uk/news/rss.xml';

$response = curl_get($url);
$xml = simplexml_load_string($response);

echo $response;

foreach ($xml->channel->item as $item) {
echo $item->title . "\n";
}

Extracted from the book "RESTful PHP Web Services" by Samisa Abeysinghe, 2008

?>

Creation of a REST/JSON webservice

Here below, I will show how to create a webservice with data in JSON format through a simple example (a function which gives the double of a given number):


 code for creation_service_rest.php

<?php


function double($val)

{

   return $val * 2;

}

if($_GET['arg']!='' && $_GET['function']=='double')

{

   $value = @call_user_func($_GET['function'], $_GET['arg']);

   $result['response']['value']=$value;
   $result['error']['code'] = '0';
   $result['error']['message'] = '0K';

}

else

{

   $result['response']['value']=NULL;
   $result['error']['code'] = '1';
   $result['error']['message'] = "RequĂȘte Invalide". ' avec function '.$_GET['function'].' et argument '.$_GET['arg'];

}

 echo json_encode($result);
?>

cf. http://notos.fr/blog/index.php?article23/exemple-de-web-services-en-php 

Tuesday 9 September 2014

Calling a REST Web service method through URL

Instead of using the soapclient library from PHP, a  REST (Representational State Transfer) webservice can be consumed by passing method and parameters directly through  the URL.
Here below, a function "Acces_REST_WS" has been defined to get the response of a web service (through the example of Chronopost webservice giving the information of a relay point from a relay idendifier)  giving the URL of  the webservice along with the applied method and parameters  :

<?php
    $sUrl ="https://www.chronopost.fr/recherchebt-ws-cxf/PointRelaisServiceWS/rechercheDetailPointChronopostInter?";
 
   $parameters = http_build_query(array(
'accountNumber' => 'XXXXXX',
'password' => 'XXXXXX',
'identifiant' => '2711R',
'countryCode' => 'FR',
'language' => 'FR'
), '&');

    $reponse = Acces_Rest_WS($sUrl,$parameters);

    function Acces_Rest_WS($sUrl, $parameters)
    {
        $aErrors = array();
        $bError = false;
     
        $url =$sUrl.$parameters;
     
        $result = URLToXml($url);
     
        // transformer le fichier XML en tableau
        $listePointRelais = json_decode(XmlToJson($result), true);

        //tester les codes erreurs
        $errorCode = $listePointRelais['soapBody']['ns1rechercheDetailPointChronopostInterResponse']['return']['errorCode'];

        if ($errorCode != '0')
        {
            // en cas d'erreur, rechercher le message d'erreur
            $bError = true;
            $errormessage = $listePointRelais['soapBody']['ns1rechercheDetailPointChronopostInterResponse']['return']['errorMessage'];
            $aErrors[] = $errorCode." : ".$errormessage ;
        }

        // absence d'erreur
        if (false === $bError)
        {
            $listePointRelais = $listePointRelais['soapBody'] ['ns1rechercheDetailPointChronopostInterResponse']['return']['listePointRelais'];
            $listePointRelais = isset($listePointRelais) ? $listePointRelais : array();
            if (!isset($listePointRelais[0]))
            {
                $listePointRelais = array(
                    0 => $listePointRelais
                );
            }
            $relays = array();

            foreach ($listePointRelais as $PointRelais)
            {
                if (!isset($PointRelais['identifiant']))
                {
                    continue;
                }
                $relay = array(
                    'label' => $PointRelais['nom'],
                    'code' => $PointRelais['identifiant'],
                    'id' => $PointRelais['identifiant'],
                    'address_line1' => $PointRelais['adresse1'],
                    'address_postal_code' => $PointRelais['codePostal'],
                    'address_city' => $PointRelais['localite'],
                    'relay_type' => 'ChronoRelais',
                    'lat' => isset($PointRelais['coordGeolocalisationLatitude']) ? $PointRelais['coordGeolocalisationLatitude'] : null,
                    'lng' => isset($PointRelais['coordGeolocalisationLongitude']) ? $PointRelais['coordGeolocalisationLongitude'] : null,
                    'country_code' => $PointRelais['codePays'],
                    'hours' => array()
                );

                $jours = array (0 =>'sun',1=>'mon',2=>'tue',3 =>'wed',4=>'thu',5=>'fri',6=>'sat');

                foreach ($PointRelais['listeHoraireOuverture'] as $day)
                {
                    $jour= $jours[$day['jour']];

                    if (isset($day['listeHoraireOuverture']))
                    {
                        $relay['hours'][$jour] = array(
                            'am' => isset($day['listeHoraireOuverture'][0]) ? array(
                                $day['listeHoraireOuverture'][0]['debut'],
                                $day['listeHoraireOuverture'][0]['fin']
                            ) : null,
                            'pm' => isset($day['listeHoraireOuverture'][1]) ? array(
                                $day['listeHoraireOuverture'][1]['debut'],
                                $day['listeHoraireOuverture'][1]['fin']
                            ) : null
                        );
                    }
                    else
                    {
                        $relay['hours'][$jour] = null;
                    }
                }
            }
        }

      return   array(
            'request' => array(
                'url' => $sUrl,
                'options' => array(),
                'parameters' => $parameters
            ),
            'response' => $relay,
            'errors' => $aErrors
        );
    }
    function XmlToJson($fileContents)
    {
        $fileContents = str_replace(array(
            "\n",
            "\r",
            "\t"
        ), '', $fileContents);
        $fileContents = trim(str_replace('"', "'", $fileContents));
        $fileContents = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $fileContents);
        $fileContents = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $fileContents);
        $fileContents = preg_replace('/[a-zA-Z]+:([a-zA-Z]+[=>])/', '$1', $fileContents);
        $simpleXml = @simplexml_load_string($fileContents);
     
        //$tab = (array) $simpleXml;
     
        $json = json_encode($simpleXml);
        return $json;
    }
 
    function URLToXml($url)
    {
       // create curl resource
        $curl = curl_init($url);

        curl_setopt($curl, CURLOPT_FAILONERROR, true);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $result = curl_exec($curl);
     
        //close curl resource to free up system resources
        curl_close($curl);  
        return $result;
    }
?>




Monday 8 September 2014

How to transform XML file into an array ?

The method I have been using to solve that issue is to convert data in these three steps:
1- apply  the function called "simplexml_load_string" to transform an XML content into XML object
2- convert the XML object into JSON format with the "json_encode" function
3- convert the JSON data to an array using  the "json_decode" function


Here the function I have been using when working with webservices  (through URL):

    $tab = json_decode(XmlToJson($xml), true);

    function XmlToJson($fileContents)
    {
        $fileContents = str_replace(array(
            "\n",
            "\r",
            "\t"
        ), '', $fileContents);
        $fileContents = trim(str_replace('"', "'", $fileContents));
        $fileContents = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $fileContents);
        $fileContents = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $fileContents);
        $fileContents = preg_replace('/[a-zA-Z]+:([a-zA-Z]+[=>])/', '$1', $fileContents);
        $simpleXml = @simplexml_load_string($fileContents);
       
        //$tab = (array) $simpleXml;
       
        $json = json_encode($simpleXml);
        return $json;
    }

How to get XML/JSON content from a specified URL address ?

 XML (along with JSON) becomes the standart format to render data through internet (cf. consumption of web services).

One way to solve that issue is to use the cURL library (the client URL library) :

Here below is the PHP function I have been using in such case :

/**
* @param str $url
* @return str $content
*/
    function URLToXml($url)
    {
       // create curl resource
        $curl = curl_init($url);

        curl_setopt($curl, CURLOPT_FAILONERROR, true);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $content = curl_exec($curl);
     
        //close curl resource to free up system resources

        curl_close($curl);

        return $content;
    }


Note :
"For accessing services we need an HTTP client. We can also use file_get_contents (http://www.php.net/file_get_contents) to access not only local files but
also those located on remote servers over HTTP.
However, file_get_contents uses GET, you would need considerable extra work to use a different verb like POST. Also, fopen wrappers need to be enabled to let file_get_contents() access remote files. System administrators may disable fopen wrappers due to security concerns.


The solution to the limitations associated with file_get_contents is to use an HTTP client library such as CURL (http://www.php.net/curl). CURL PHP API is a wrapper of libcurl (http://curl.haxx.se/libcurl/), a library that allows you to communicate using many different types of protocols. It supports HTTP verbs such as POST and PUT in addition to GET.


 [..]
HTTP verbs and how they apply while using REST web services:
GET : Retrieves a resource identified by a URI.
POST : Sends a resource to the server. Updates the resource in the location identified by the URI.
PUT : Sends a resource to the server, to be stored in the location identified by the URI.
DELETE : Deletes a resource identified by a URI.
HEAD : Retrieves the metadata of a resource identified by the URI.

"
(extracted from RESTful PHP Web Services, Samisa Abeysinghe