Wednesday, July 3, 2013

using php CURL get the contents of a site with example to get PNR status of Indian railways.

Declaration and Warning: This is done just for example and I declare i do not have any intention to Create DOS, or it is not indented to harm http://indianrail.gov.in. I am ready to remove the post as well as hosted file if this is going to harm indianrail.gov.in in any way. I am not responsible for anyone using this code for any reason. Use this code at your own risk.

Note: This code provided no longer work Latest code can be found in the post here

I have just been going through the curl in PHP and trying to use it. Here is the small example to use curl.
The Idea here is to create a php API to get the PNR status of the given PNR number in json format or in XML.



Demo:
http://www.kirant400.com/irctc/pnr.php?pnrno=4565206151&rtype=XML Link no longer works
this return:
<?xml version="1.0"?>
<result>
<status>OK</status>-
<data>
<pnr>4565206151</pnr>
<train_name>TRAIN EXP</train_name>
<train_number>26536</train_number>
<from>SRC</from>
<to>DES</to>
<reservedto>DES</reservedto>
<board>SRC</board>
<class>SL</class>
<travel_date>18- 7-2033</travel_date>-
<passenger>
  <seat_number>W/L 41,GNWL</seat_number>
  <status>W/L 6</status>
  <seat_number>W/L 42,GNWL</seat_number>
  <status>W/L 7</status>
</passenger></data></result>>

http://www.kirant400.com/irctc/pnr.php?pnrno=4565106151Link no longer works
this return:
{"status":"OK",
  "data":
            {"pnr":"4565206151",
              "train_name":"TRAIN EXP",
              "train_number":"26536",
              "from":"SRC",
              "to":"DES",
              "reservedto":"DES",
              "board":"SRC",
              "class":" SL",
              "travel_date":"18- 7-2033",
              "passenger":
                                  [{"seat_number":"W\/L   41,GNWL",
                                      "status":"W\/L    6"},
                                   {"seat_number":"W\/L   42,GNWL",
                                      "status":"W\/L    7"}
                                  ]
       }
}
Usage:
Status can be retrieved using POST and GET the parameter that need to provide are
pnrno  and rtype
pnrno: This is a mandatory pnr number for the ticket.Default value is ""
rtype: This is an optional parameter to specify the result type if it is JSON or XML. Provide XML to get XML result. Default value is JSON.

Now How it is done.

1. Get he POST or GET parameter.
2. Fill the POST parameter required for site.
3. use curl to get the web page.
4. parse the result for the particular tags.
5. form the result either XML or JSON and send the result back to the client.

Get the Parameter:
pnrno and rtype is kept in a variable using the below code:
$pnt_no = isset($_POST['pnrno'])? $_POST['pnrno']:(isset($_GET['pnrno'])?$_GET['pnrno']:'');
$rtype = isset($_POST['rtype'])? $_POST['rtype']:(isset($_GET['rtype'])?$_GET['rtype']:'');
Fill the parameter for the site:
for http://indianrail.gov.in the post parameter required are:
'lccp_pnrno1' and 'submit'
'lccp_pnrno1' is for the pnrno and 'submit' hold a fixed string value.

//Create array of data to be posted
$post_data ['lccp_pnrno1'] = $pnt_no;
$post_data['submit'] = "Wait For PNR Enquiry!";
//traverse array and prepare data for posting (key1=value1)
foreach ( $post_data as $key => $value) {
    $post_items[] = $key . '=' . $value;
}
//create the final string to be posted using implode()
$post_string = implode ('&', $post_items);
Using Curl to get the web page:

Fill the required parameter to the web page and then use curl to get the web page.
//create cURL connection
$curl_connection =
  curl_init('http://www.indianrail.gov.in/cgi_bin/inet_pnrstat_cgi.cgi');
//set options
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curl_connection, CURLOPT_USERAGENT,
  "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 1);
//set data to be posted
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_string);
//perform our request
$result = curl_exec($curl_connection);
//show information regarding the request
//print_r(curl_getinfo($curl_connection));
//echo curl_errno($curl_connection) . '-' .
//                curl_error($curl_connection);
//close the connection
curl_close($curl_connection);


Parse the result:
Here I did not use any DOM or any other data structure. I have just used regular expressions to extract the contents that is required.

$matches = array();
preg_match_all('/<TD class="table_border_both">(.*)<\/TD>/',$result,$matches);
//var_dump($matches);
$resultVal = array(
    'status'    =>    "INVALID",
    'data'      =>    array()            
);
if (count($matches)>1&&count($matches[1])>8) {
 $arr = $matches[1];
 $i=0;
 $j=0;
 $tmpValue =array(
          "pnr" => $pnt_no,
          "train_name" => "",
          "train_number" => "",
          "from" => "",
          "to" => "",
          "reservedto" => "",
          "board" => "",
          "class" => "",
          "travel_date" => "",
          "passenger" => array()
 );
 $tmpValue['train_number'] = $arr[0];
 $tmpValue['train_name'] = $arr[1];
 $tmpValue['travel_date'] = $arr[2];
 $tmpValue['from'] = $arr[3];
 $tmpValue['to'] = $arr[4];
 $tmpValue['reservedto'] = $arr[5];
 $tmpValue['board'] = $arr[6];
 $tmpValue['class'] = $arr[7];
 $stnum="";
 foreach ($arr as $value) {
  $i++;
  if($i>8){
   $value=trim(preg_replace('/<B>/', '', $value));
   $value=trim(preg_replace('/<\/B>/', '', $value));

   $ck=$i%3;
    if($ck==1){  
     $stnum = $value;
    }
    else if($ck==2) {
      array_push($tmpValue["passenger"],array(
           "seat_number" => $stnum,
           "status" => $value
        ));
    }
  }
 }
 $resultVal['data'] = $tmpValue;
 $resultVal['status'] = 'OK';
}


Form the result in XML and JSON and send to client:
I have used two function for this conversion. One for Array to JSON and other for Array to XML

function array2json($arr) {
    if(function_exists('json_encode')) return json_encode($arr); //latest versions of PHP already have this functionality.
    $parts = array();
    $is_list = false;
    //Find out if the given array is a numerical array
    $keys = array_keys($arr);
    $max_length = count($arr)-1;
    if(($keys[0] == 0) and ($keys[$max_length] == $max_length)) {//See if the first key is 0 and last key is length - 1
        $is_list = true;
        for($i=0; $i<count($keys); $i++) { //See if each key corresponds to its position
            if($i != $keys[$i]) { //A key fails at position check.
                $is_list = false; //It is an associative array.
                break;
            }
        }
    }
    foreach($arr as $key=>$value) {
        if(is_array($value)) { //Custom handling for arrays
            if($is_list) $parts[] = array2json($value); /* :RECURSION: */
            else $parts[] = '"' . $key . '":' . array2json($value); /* :RECURSION: */
        } else {
            $str = '';
            if(!$is_list) $str = '"' . $key . '":';
            //Custom handling for multiple data types
            if(is_numeric($value)) $str .= $value; //Numbers
            elseif($value === false) $str .= 'false'; //The booleans
            elseif($value === true) $str .= 'true';
            else $str .= '"' . addslashes($value) . '"'; //All other things
            // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
            $parts[] = $str;
        }
    }
    $json = implode(',',$parts);
 
    if($is_list) return '[' . $json . ']';//Return numerical JSON
    return '{' . $json . '}';//Return associative JSON
}
// function definition to convert array to xml
function array2xml($student_info, &$xml_student_info) {
    foreach($student_info as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_student_info->addChild("$key");
                array2xml($value, $subnode);
            }
            else{
                array2xml($value, $xml_student_info);
            }
        }
        else {
            $xml_student_info->addChild("$key","$value");
        }
    }
}


And this selection of sending the result is from the rtype provided.

if($rtype=='XML'){
$xmlresult = new SimpleXMLElement("<?xml version=\"1.0\"?><result></result>");
array2xml($resultVal,$xmlresult);
echo $xmlresult->asXML();
}
else
echo array2json($resultVal);


Conclusion:
curl and php are powerful. This example helps us to know how to use CURL in PHP and some Regular expressions. This example provides an API to fetch PNR status of the Indian railway system.
The working example is hosted on:

 http://www.kirant400.com/irctc/pnr.phpLink no longer works


Contributors