converting from XML -> PHP Array -> Json Encode - php

I am setting up an input autocomplete using jquery tokeninput plugin and XML data.
I have an XML file structured as shown:
<?xml version="1.0" encoding="UTF-8"?>
<majors>
<major program="GCIS">Computing & Info Sci (PHD)</major>
<major program="UINT">Business Administration (AAS)</major>
etc..
</majors>
I load it into PHP:
$majors = simplexml_load_file('../ajax/majors.xml');
I then want to do the following things:
reformat each <major>element into string, including program attribute
(ex: <major program="GCIS">Computing & Info Sci (PHD)</major> turns into string GCIS - Computing & Info Sci (PHD)
run the converted string through a filter function. The filter function checks for strpos($convertedString, $userQuery) and returns true/false if the user's query is present
elements which DO contain the $userQuery are all then encoded with json_encode($arr)
return JSON data.
This is the code I currently have... I can't seem to get the formatting / filtering to work correctly.
if(isset($_POST['query']) ) {
$majors = simplexml_load_file('../ajax/majors.xml');
# iterate through.
foreach ($majors as $key => $value) {
$arr = array('major' => $value['program'] . " - " . $value);
}
# filter the response using our query
$arr = array_filter($arr, 'filterArrayWithQuery');
# JSON-encode the response
$json_response = json_encode($arr);
# Return the response
return $json_response;
}
# ensures that the search query is present
function filterArrayWithQuery( $string ) {
return !strpos( $string, $query ) === false;
}
The end-result JSON output should look like this:
{"major":"GCIS - Computing & Info Sci (PHD)","major":"UINT - Business Administration (AAS)"}

In your iterate through line, you are not appending new entries -
# iterate through.
foreach ($majors as $key => $value) {
$arr[] = array('major' => $value['program'] . " - " . $value);
// ^^
}
With this the output would be-
[{"major":"GCIS - Computing & Info Sci (PHD)"},{"major":"UINT - Business Administration (AAS)"}]

Try this:
function convert($xml) {
# ensures that the search query is present
function filterArrayWithQuery($string) {
static $query = null;
if (is_null($query) && isset($_POST['query'])) $query = $_POST['query'];
return !$query || strpos($string, $_POST['query']) !== false;
}
$majors = simplexml_load_string($xml);
$arr = array();
# iterate through
foreach ($majors as $key => $value) {
$arr[] = array('major' => $value['program'] . " - " . htmlentities($value));
}
# filter the response using our query
$arr = array_filter($arr, 'filterArrayWithQuery');
# Return the response (JSON-encoded)
return json_encode(array('majors' => $arr));
}
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<majors>
<major program="GCIS">Computing & Info Sci (PHD)</major>
<major program="UINT">Business Administration (AAS)</major>
</majors>
XML;
$_POST['query'] = 'Info';
echo convert($xml);

Thank you to the input I received, however I was able to figure out the solution.
Here is the final PHP script for those interested.
<?php
# vars
$reqMethod = $_SERVER['REQUEST_METHOD'];
$ref = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : "http://www.google.com";
$allowedHosts = array('redacted', 'localhost');
$majors = null;
$arr = array();
$query = isset($_POST['q']) ? $_POST['q'] : "";
# confirm request is being sent from where we allow.
if ( $reqMethod != 'POST' || !in_array(parse_url($ref, PHP_URL_HOST), $allowedHosts) ) {
header('Location: ' . $ref);
} else {
# load in XML
$majors = simplexml_load_file('../ajax/majors.xml');
# iterate through XML. if element contains query, add it to an array.
foreach ($majors as $key => $value) {
if( !stristr( $value, $query ) === false ){
$arr[] = array('major' => $value['program'] . " - " . $value);
}
}
# Return the response - JSON encoded
header('Content-type: application/json');
echo json_encode($arr);
}
?>

Related

Show only a specific part of html response in php

I am trying to get tracking information from amazon using provided url
https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302
I am getting response using file_get_contents() function in php,
what I want is to show only that part of the response which contains the tracking information as an output of my php script and eliminate/hide all the unnecessary content from file_get_contents() response.
One way to do what you're looking for is use DomDocument to filter out the json data in the source ($file) and then use a recursive function to get the elements you need.
You can set the elements you need using an array, $filter. In this example we've taken a sample of some of the available data, i.e. :
$filter = [
'orderId', 'shortStatus', 'promiseMessage',
'lastTransitionPercentComplete', 'lastReachedMilestone', 'shipmentId',
];
The code
<?php
$filename = 'https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302';
$file = file_get_contents($filename);
$trackingData = []; // store for order tracking data
$html = new DOMDocument();
#$html->loadHTML($file);
foreach ($html->getElementsByTagName('script') as $a) {
$data = $a->textContent;
if (stripos($data, 'shortStatus') !== false) {
$trackingData = json_decode($data, true);
break;
}
}
// set the items we need
$filter = [
'orderId', 'shortStatus', 'promiseMessage',
'lastTransitionPercentComplete', 'lastReachedMilestone', 'shipmentId',
];
// invoke recursive function to pick up the data items specified in $filter
$result = getTrackingData($filter, $trackingData);
echo '<pre>';
print_r($result);
echo '</pre>';
function getTrackingData(array $filter, array $data, array &$result = []) {
foreach($data as $key => $value) {
if(is_array($value)) {
getTrackingData($filter, $value, $result);
} else {
foreach($filter as $item) {
if($item === $key) {
$result[$key] = $value;
}
}
}
}
return $result;
}
Output:
Array
(
[orderId] => 203-2171364-3066749
[shortStatus] => IN_TRANSIT
[promiseMessage] => Arriving tomorrow by 9 PM
[lastTransitionPercentComplete] => 92
[lastReachedMilestone] => SHIPPED
[shipmentId] => 23796758607302
)
Try this
<?php
$filename = 'https://www.amazon.co.uk/progress-tracker/package/ref=pe_3187911_189395841_TE_typ?_encoding=UTF8&from=gp&itemId=&orderId=203-2171364-3066749&packageIndex=0&shipmentId=23796758607302';
$file = file_get_contents($filename);
$html = new DOMDocument();
#$html->loadHTML($file);
foreach($html->getElementsByTagName('span') as $a) {
$property=$a->getAttribute('id');
if (strpos($property , "primaryStatus"))
print_r($property);
}
?>
It should show "Arriving tomorrow by 9 PM" status.

Fatal Error occurring while passing html data in array using simple html dom php

I am trying to extract data using simple html dom and it works fine when i am passing html file or url to it i-e :-
$html = file_get_html('sv.html');
$foo = $html->find('p[plaintext^=EDUCATION AND TRAINING]');
$items3 = array();
foreach ($pinfo as $keypi) {
# code...
//var_dump($key);
//print_r($key);
while ( $keypi->nextSibling() ) {
if ( $keypi->nextSibling() == TRUE) {
//echo $key->nextSibling();
$keypi = $keypi->nextSibling();
$varcpi = $keypi->plaintext;
//$cnt++;
//echo "cnt=$cnt<br><br><br>";
}
if ( trim($varcpi) == "JOB APPLIED FOR" ){
break;
}
$items3[] = $varcpi;
}
}
$trimmedArray = array_map('trim', $items3);
$b = array_values(array_filter($trimmedArray));
var_dump($b);
Problem occurs when i pass html file in array as i am trying to pass it html data that was converted from pdf using PDFTOHTML (a php library) in code given below $page contains html data if i echo $page it's showing html accurate but when i pass it as array to simple html dom it's not working :-
include 'vendor/autoload.php';
$pdf = new \TonchikTm\PdfToHtml\Pdf('cv.pdf', [
'pdftohtml_path' => 'C:/wamp64/www/new/poppler-0.51/bin/pdftohtml.exe',
'pdfinfo_path' => 'C:/wamp64/www/new/poppler-0.51/bin/pdfinfo.exe'
]);
foreach ($pdf->getHtml()->getAllPages() as $page) {
$my_array[] = $page . '<br/>';
}
//$html = file_get_html('sv.html');
$pinfo = $my_array->find('p[plaintext^=PERSONAL INFORMATION]');
where $my_array[] contains html data is and showing accurate results but when i pass it to simple html dom here :-
$pinfo = $my_array->find('p[plaintext^=PERSONAL INFORMATION]');
instead of this:-
$html = file_get_html('sv.html');
it shows error :-
( ! ) Fatal error: Call to a member function find() on array in C:\wamp64\www\new\upload.php on line 56
i have tried using str_get_html which does not any error but also it's not showing any results :-
foreach ($pdf->getHtml()->getAllPages() as $page) {
$html = str_get_html($page);
$pinfo = $html->find('p[plaintext^=PERSONAL INFORMATION]');
$items3 = array();
foreach ($pinfo as $keypi) {
# code...
//var_dump($key);
//print_r($key);
while ( $keypi->nextSibling() ) {
if ( $keypi->nextSibling() == TRUE) {
//echo $key->nextSibling();
$keypi = $keypi->nextSibling();
$varcpi = $keypi->plaintext;
//$cnt++;
//echo "cnt=$cnt<br><br><br>";
}
if ( trim($varcpi) == "JOB APPLIED FOR" ){
break;
}
// echo $varc;
$items3[] = $varcpi;
}
}
$trimmedArray = array_map('trim', $items3);
$b = array_values(array_filter($trimmedArray));
var_dump($b);
}
Output:-
C:\wamp64\www\new\upload.php:81:
array (size=0)
empty
C:\wamp64\www\new\upload.php:81:
array (size=0)
empty
It would be great if anyone help me out here!!!

What is the best way to search through an array to return the key of a sub value

I'm trying to filter an array (derived from a json object), so as to return the array key based on the value. I'm not sure if array search $key = array_search($value, $array); is the best way to do this (I can't make it work), and I think there must be a better way.
So far I've got this, but it isn't working. Grateful for any help!
public function getBedroomData(array $data,$num_beds = null,$type) {
$data = (array) $data;
if($num_beds > 0) {
$searchstring = "avg_".$num_beds."bed_property_".$type."_monthly";
} else {
$searchstring = "avg_property_".$type."_monthly";
}
$avg_string = array_search($data, $searchstring);
return $avg_string;
}
The array consists of average property prices taken from the nestoria api as follows:
http://api.nestoria.co.uk/api?country=uk&pretty=1&action=metadata&place_name=Clapham&price_type=fixed&encoding=json
This returns a long json object. My problem is that the data isn't consistent - and I'm looking for the quickest (run time) way to do the following:
$data['response']['metadata']['0'] //= data to return, [0] unknown
$data['response']['metadata']['0']['metadata_name'] = "avg_1bed_property_rent_monthly" //= string I know!
$data['response']['metadata']['1'] //= data to return, [1] unknown
$data['response']['metadata']['1']['metadata_name'] = "avg_1bed_property_buy_monthly" //= string I know!
$data['response']['metadata']['2'] = //= data to return, [2] unknown
$data['response']['metadata']['2']['metadata_name'] = "avg_2bed_property_buy_monthly" //= string I know!
.....
.....
.....
$data['response']['metadata']['10'] = avg_property_rent_monthly
$data['response']['metadata']['11'] = avg_property_buy_monthly
$data['response']['metadata'][most_recent_month] = the month reference for getting the data from each metadata list..
It isn't possible to filter the initial search query by number of bedrooms as far as I can work out. So, I've just been array slicing the output to get the information I've needed if bedrooms are selected, but as the data isn't consistent this often fails.
To search inside that particular json response from nestoria, a simple foreach loop can be used. First off, of course call the json data that you need. Then, extract the whole data, the the next step if pretty straightforward. Consider this example:
$url = 'http://api.nestoria.co.uk/api?country=uk&pretty=1&action=metadata&place_name=Clapham&price_type=fixed&encoding=json';
$contents = file_get_contents($url);
$data = json_decode($contents, true);
$metadata = $data['response']['metadata'];
// dummy values
$num_beds = 1; // null or 0 or greater than 0
$type = 'buy'; // buy or rent
function getBedroomData($metadata, $num_beds = null, $type) {
$data = array();
$searchstring = (!$num_beds) ? "avg_property_".$type."_monthly" : "avg_".$num_beds."bed_property_".$type."_monthly";
$data['metadata_name'] = $searchstring;
$data['data'] = null;
foreach($metadata as $key => $value) {
if($value['metadata_name'] == $searchstring) {
$raw_data = $value['data']; // main data
// average price and data points
$avg_price = 0;
$data_points = 0;
foreach($raw_data as $index => $element) {
$avg_price += $element['avg_price'];
$data_points += $element['datapoints'];
}
$data_count = count($raw_data);
$price_average = $avg_price / $data_count;
$data_points_average = $data_points / $data_count;
$data['data'][] = array(
'average_price' => $price_average,
'average_datapoints' => $data_points_average,
'data' => $raw_data,
);
}
}
return $data;
}
$final = getBedroomData($metadata, $num_beds, $type);
print_r($final);

Grab the Result from Mysql, convert contents of link into XML, then output

UPDATED CODE
<?php
#header( "Content-Type: application/xml" );
function doLoop($arr = array())
{
global $newsStory;
foreach( $arr as $r )
{
//check if we're dealing with an array (multiple links)
if ( is_array($r) === true )
{
//loop through the array and work with each link
foreach ( $r as $link_)
//check if link is an array
if ( is_array($link_) ){doLoop($link_); continue;}
// //end of third dimension array found
## gets url from database as outlined above.
$xmlUrl = $link_;
#Loads the url above into XML
$ConvertToXml = simplexml_load_file($xmlUrl);
# -> Setup XML
$newsStory[] = $ConvertToXml->channel->item;
}//end of loop
continue;//move on
}//end of is array
//if we get here, we know that only $r is not an array, just a value, so:
## gets url from database as outlined above.
$xmlUrl = $r;
#Loads the url above into XML
#$ConvertToXml = simplexml_load_file($xmlUrl);
# -> Setup XML
#$newsStory[] = $ConvertToXml->channel->item;
$newsStory[] = $r;
print_r($newsStory);
}//end of function
## Loop through results from mysql
try{
#connection string
// $dbconn = new PDO('mysql:host=localhost;port=3306;dbname=thedb',array(PDO::ATTR_PERSISTENT => true));
$dbconn = new PDO('mysql:host=localhost;port=3306;dbname=thedb','root','toshiba1',array(PDO::ATTR_PERSISTENT => true));
$q = $dbconn->prepare("SELECT FW_ArtSrcLink FROM FW_ArtSrc WHERE OneSet=1 and leagID=20");
#call stored proc
$q->execute();
#get the rows into an array
$result = $q->fetchAll();
$newsStory = array();
doLoop($result);
# -----> Load News Stories
for($i = 0;$i<sizeof($newsStory); $i++){
//print_r($newsStory);
echo "<a href='".$newsStory[$i]->link."'>".$newsStory[$i]->title."</a><br />";
echo $newsStory[$i]->description;
echo '<hr>';
} // for()
} // try
catch(Exception $e){
$errorPg='errors/fanwire_loop.php';
$pageDateOfError = $e->getMessage().'on:'.'aggregate_looping.php'.' on '.date('l jS \of F Y h:i:s A'); # inc. details of error
file_put_contents($errorPg,$pageDateOfError, FILE_APPEND | LOCK_EX);
} // catch
?>
Output of print_r():
Another example of output from print_r():
This is beginning to get really confusing.
Your code is a mess, so I'm going to start off fresh here.
You say print_r($result) returns this:
Array ( [0] => Array ( [FW_ArtSrcLink] => http://sports.espn.go.com/espn/rss/tennis/news [0] => http://sports.espn.go.com/espn/rss/tennis/news ) [1] => Array ( [FW_ArtSrcLink] => http://sports.yahoo.com/tennis/rss.xml [0] => http://sports.yahoo.com/tennis/rss.xml ) [2] => Array ( [FW_ArtSrcLink] => http://bleacherreport.com/articles;feed?tag_id=12 [0] => http://bleacherreport.com/articles;feed?tag_id=12 )
So there are three arrays in that var, each containing two links.
So, two simple foreach loops should easily be able to deal with this:
foreach ($result as $value )
{
if ( is_array($value) )
{
foreach ( $value as $secondValue )
{
}
continue;
}
}
Should be that simple.
We will have all the processing in a function.
function processLink( $link , $appendArr )
{
## gets url from database as outlined above.
$xmlUrl = $link;
#Loads the url above into XML
$ConvertToXml = simplexml_load_file($xmlUrl);
# -> Setup XML
$appendArr[] = $ConvertToXml->channel->item;
}
So, the end result should be:
function processLink( $link , $appendArr )
{
## gets url from database as outlined above.
$xmlUrl = $link;
#Loads the url above into XML
$ConvertToXml = simplexml_load_file($xmlUrl);
# -> Setup XML
$appendArr[] = $ConvertToXml->channel->item;
}
$dbconn = new PDO('mysql:host=localhost;port=3306;dbname=thedb','root','toshiba1',array(PDO::ATTR_PERSISTENT => true));
$q = $dbconn->prepare("SELECT FW_ArtSrcLink FROM FW_ArtSrc WHERE OneSet=1 and leagID=20");
$q->execute();
$result = $q->fetchAll();
$newsStory = array();
foreach ($result as $value )
{
if ( is_array($value) )
{
foreach ( $value as $secondValue )
{
processLink($secondValue , &$newsStory);
}
continue;
}
processLink($value , &$newsStory);
}
print_r($newsStory);

Turning off multidimensional arrays via POST in PHP

Is there a way to turn off the PHP functionality for Submitting a multidimensional array via POST with php?
So that submission of <input type="text" name="variable[0][1]" value="..." /> produces a $_POST like so...
array (
["variable[0][1]"] => "...",
)
NOT like so:
array (
["variable"] => array(
[0] => array (
[1] => "..."
),
),
)
I'm thinking/hoping an obscure PHP.ini directive or something... ?
No, but nothing stops you from fetching the query string (through $_SERVER['QUERY_STRING']) and parsing it manually. For instance:
$myGET = array();
foreach (explode("&", $_SERVER['QUERY_STRING']) as $v) {
if (preg_match('/^([^=])+(?:=(.*))?$/', $v, $matches)) {
$myGET[urldecode($matches[1])] = urldecode($matches[2]);
}
}
I should think not. What exactly are you trying to do?
You could use variable(0)(1) or variable_0_1 as names for example.
Don't believe you can do that. I also don't understand why you'd need to. But this should work:
$_POST['variable'] = array(array('abc','def'),array('ddd','ggg'));
print_r(flatPost('variable'));
function flatPost($var)
{
return enforceString($_POST[$var], $var);
}
function enforceString($data, $preKey = '')
{
if(!is_array($data))
{
return array($preKey . $data);
}
$newData = array();
foreach($data as $key => &$value)
{
$element = enforceString($value, $preKey . '[' . $key . ']');
$newData = array_merge($newData, $element);
}
return $newData;
}
It's a little over the top, but if necessary you could manually parse the request body.
<?php
if(!empty($_POST) && $_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded') {
$_post = array();
$queryString = file_get_contents('php://input'); // read the request body
$queryString = explode('&', $queryString); // since the request body is a query string, split it on '&'
// and you have key-value pairs, delimited by '='
foreach($queryString as $param) {
$params = explode('=', $param);
if(array_key_exists(0, $params)) {
$params[0] = urldecode($params[0]);
}
if(array_key_exists(1, $params)) {
$params[1] = urldecode($params[1]);
}
else {
$params[1] = urldecode('');
}
$_post[$params[0]] = $params[1];
}
$_POST = $_post;
}
?>

Categories