I've recently changed my web hosting and unfortunately the administrator has disabled file_get_content and some other functions.
The aim of this script is to get iOS device's information directly from device. Before, I was using this code to do so:
$content = file_get_contents('php://input');
file_put_contents("data.txt", $content);
And the result was like this (in data.txt)
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IMEI</key>
<string>01 257233 621346 0</string>
<key>PRODUCT</key>
<string>iPhone2,1</string>
<key>SERIAL</key>
<string>5K1124GHEDG</string>
<key>UDID</key>
<string>07cc825055gftr4edsa3f06d0373376a7664a66a</string>
<key>VERSION</key>
<string>10B329</string>
</dict>
</plist>
As the Curl function is enabled on my server, I tried this code in some different ways, but didn't work. The data.txt is emptied as a result!
$ch = curl_init();
$timeout = 0;
curl_setopt ($ch, CURLOPT_URL, "php://input");
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$contents = curl_exec($ch);
curl_close($ch);
file_put_contents("data.txt", $contents);
UPDATED:
Let me explain how it works. We direct users to a profile which is stored on our server(e.g device.mobileconfig). Once users click on that, they will be asked to install that. Its content is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<dict>
<key>URL</key>
<string>http://mywebsite.com/get.php</string>
<key>DeviceAttributes</key>
<array>
<string>UDID</string>
<string>VERSION</string>
<string>PRODUCT</string>
<string>SERIAL</string>
</array>
</dict>
<key>PayloadDescription</key>
<string>Install to get device info</string>
<key>PayloadDisplayName</key>
<string>UDID Finder</string>
<key>PayloadIdentifier</key>
<string>com.myud.ir</string>
<key>PayloadOrganization</key>
<string>MyUD.ir</string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Profile Service</string>
<key>PayloadUUID</key>
<string>57A223FD-F675-90B1-8F43-22D3FC3BC181</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
The profile runs get.php to fetch data from device. I tried Cristian's one but did not work. I probably have a mistake some where. The get.php is:
<?php
$xml = new SimpleXMLElement('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"/>');
$dict = $xml->addChild('dict');
foreach ($_POST as $item => $value) {
$dict->addChild('string', $item);
$dict->addChild('key', $value);
}
file_put_contents("data.txt", trim(str_replace('<?xml version="1.0"?>', '', $xml->asXML())));
?>
P.S.
I just need the data between
<dict></dict>
Assuming that php://input is a read-only stream that allows you to read raw data from the request body, you can solve this problem by fetching $_POST data then create an xml document using php's SimpleXMLElement class witch then will be written to data.txt.
You can proceed in this way:
$xml = new SimpleXMLElement('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"/>');
$dict = $xml->addChild('dict');
foreach ($_POST as $item => $value) {
$dict->addChild('string', $item);
$dict->addChild('key', $value);
}
file_put_contents("data.txt", trim(str_replace('<?xml version="1.0"?>', '', $xml->asXML())));
Another solution:
$f = fopen('php://input','r');
$out = fopen('data.txt','w');
$body = "";
while( $line = fgets( $f ) ) {
$body .= $line;
}
fwrite($out, $body);
fclose($f);
fclose($out);
Thank you very much Cristian. it worked.
I also found another way which is PEAR php Component that provides lots of functions which are alternative to main php functions for those people who are struggling like me!
for instance, in my case, I uploaded the file_get_content function to the same folder and included that in get.php
instead of
$content = file_get_contents('php://input');
file_put_contents("data.txt", $content);
I'm now using
require_once 'file_get_contents.php';
$content = php_compat_file_get_contents('php://input');
file_put_contents("data.txt", $content);
Related
I'm using Curl to execute a soap request.
Now it looks like there is a mistake returned in the headers that prevents me from turning the returned string into a simplexml object with the function simplexml_load_string. Below you can find the part of the response that fails in the simplexml function:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Header><SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/><ds:Reference URI="#Body"><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue></ds:Reference><ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue></ds:SignedInfo></ds:Signature></SOAP-SEC:Signature></SOAP-ENV:Header><SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">
Is there a way to isolate the soap body content and parsing only that part with the simplexml_load_string?
Below the curl request:
$headers = array(
"Content-type: text/xml;charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"Content-length: ".strlen($xml_post_string),
);
$url = $soapUrl;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
$xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);
echo $xml->asXML();
if ($xml === false) {
echo "Failed to load XML: ";
foreach(libxml_get_errors() as $error) {
echo "<br>", $error->message;
}
} else {
var_dump($xml);
}
I don't have an answer for you right now, but you first need to separate curl from XML processing. You should start with logging your result from curl and making sure it is sane and what you expect. If it is, then move on to parsing it. curl should never break/change your data in any way, but the request itself (headers, etc.) might change the server's response.
Since I can't validate your server, I'm just going to go off of what you've provided. I've closed the <SOAP-ENV:Body> tag and converted the XML to readable, but otherwise it is untouched. This code parses the XML without a problem and then emits it exactly as expected.
$response = <<<'TAG'
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>
<SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
<ds:Reference URI="#Body">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
</ds:Reference>
<ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
</ds:SignedInfo>
</ds:Signature>
</SOAP-SEC:Signature>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"></SOAP-ENV:Body>
</SOAP-ENV:Envelope>
TAG;
$xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);
echo '<pre>';
print_r(htmlspecialchars($xml->asXML()));
echo '</pre>';
The output is exactly the same as the input except it includes the XML directive and converts the body tag to self-closing:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>
<SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
<ds:Reference URI="#Body">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
</ds:Reference>
<ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
</ds:SignedInfo>
</ds:Signature>
</SOAP-SEC:Signature>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"/>
</SOAP-ENV:Envelope>
So use this as a baseline. Write your curl response to a text file before doing anything else, and then read that text file back in and perform logic. Any transformation you apply to the string XML should also be logged and compared to make sure it is doing what you expected. On production you'd skip that but this just helps during the debugging.
Also, I'm not really sure what the point of html_entity_decode is in this. If you are receiving XML (as your request mime type specifies) then it shouldn't have any escape sequences applied to it, but maybe you have an exceptional case, too.
Just to give some example XML content, this will vary for any file but just shows how you can access the data...
<SOAP-ENV:Body
xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"
SOAP-SEC:id="Body">
<BodyContent>SomeData</BodyContent>
<OtherContent>2</OtherContent>
</SOAP-ENV:Body>
Then it would be a case of using XPath to find the <SOAP-ENV:Body> tag
$xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
$bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];
(note that as xpath() returns a list of matches, using [0] just uses the first one).
This next part depends on the message being processed, but as the example I gave has child elements with no namespace prefix, then you can extract these using ->children() and this eases access to the contents. The main part is that at this point the $bodyBlock contains this...
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">
<BodyContent>SomeData</BodyContent>
<OtherContent>2</OtherContent>
</SOAP-ENV:Body>
So to put that together in your original code...
$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($xml === false) {
echo "Failed to load XML: ";
foreach(libxml_get_errors() as $error) {
echo "<br>", $error->message;
}
} else {
// Search for the Body element (this is in the SOAP-ENV namespace)
$xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
$bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];
// If the content does not have a namespace, extract the children from the default namespace
$body = $bodyBlock->children();
// You can now access the content.
echo $body->BodyContent.PHP_EOL;
echo $body->OtherContent;
}
which outputs the two values in the body....
SomeData
2
I have a log file whose content is like the one below
2016-04-07 19:37:48 <order merchant="asc" affiliate="" id="UM9E-C01101518" date="1443723720" event_id="1" ref="GDVJT" alias="asc">
<event type="sale" date="2015-10-01 18:22:00" status_code="SA">
<sale amount="61.45" amount_usd="43.94" method="VISA" currency="CAD" processor="visa"/>
<tax amount="7.37" amount_usd="5.28" currency="CAD"/>
<payout amount="39.89" currency="USD"/>
</event>
<customer>
<name>Frank</name>
<email>frank#gmail.com</email>
<address/>
<region>BC</region>
<country>IN</country>
<zip_postal>V8V1J9</zip_postal>
<phone_number>1231231234</phone_number>
<language>EN</language>
<ip>209.13.233.227</ip>
<currency>CAD</currency>
</customer>
I am trying to extract the value of name and email from this log file.
I am using the below code:
$handle = fopen('vendorOrder.log','r') or die ('File opening failed');
while (!feof($handle)) {
$dd = fgets($handle);
$str = htmlentities($dd, ENT_XHTML);
if(preg_match("/<name>(.*)<\/name>/",$str)){
$txt = getTextBetweenTags($str, "name");
echo $txt;
}
}
fclose($handle);
function getTextBetweenTags($string, $tagname) {
$pattern = "/<$tagname>(.*)<\/$tagname>/";
preg_match($pattern, $string, $matches);
return $matches[0];
}
But it is never matching the name tag and I am not able to get the value between the tags.
I need the output as Frank.
Can someone let me know whats wrong in the code
Use simplexml_load_file() php function.
Example:
$xml=simplexml_load_file("vendorOrder.log") or die("Error: Cannot create object");
And get this value with $xml->customer->name
Maybe your XML are crashed. Try this format.
<order merchant="asc" affiliate="" id="UM9E-C01101518" date="1443723720" event_id="1" ref="GDVJT" alias="asc">
<event type="sale" date="2015-10-01 18:22:00" status_code="SA">
<sale amount="61.45" amount_usd="43.94" method="VISA" currency="CAD" processor="visa"/>
<tax amount="7.37" amount_usd="5.28" currency="CAD"/>
<payout amount="39.89" currency="USD"/>
</event>
<customer>
<datetime>2016-04-07 19:37:48</datetime>
<name>Frank</name>
<email>frank#gmail.com</email>
<address/>
<region>BC</region>
<country>IN</country>
<zip_postal>V8V1J9</zip_postal>
<phone_number>1231231234</phone_number>
<language>EN</language>
<ip>209.13.233.227</ip>
<currency>CAD</currency>
</customer>
</order>
Yup as stated use simplexml_load_file($url) ; to parse xml.
you can find examples here : http://www.w3schools.com/php/php_xml_simplexml_get.asp
Make a correction in original string with something like this:
<?php
$xml_file = 'vendorOrder.log';
$xml_content = file_get_contents( $xml_file );
$xml_content .= "\n</order>";
$xml_content = substr( $xml_content, 20 );
var_dump($xml_content);
$xml=simplexml_load_string($xml_content) or die("Error: Cannot create object");
echo $xml->customer->name;
I'm tring to process xml (website) into php array.
I have tried the following code which works for everyting in results but i need to get the totalpage which i'm not able to see how I can do this.
function get_content($url)
/// basically opens the page and stores it as a variable. Buggered if I know how it works!
{
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_HEADER, 0);
ob_start();
curl_exec ($ch);
curl_close ($ch);
$string = ob_get_contents();
ob_end_clean();
return $string;
$string = NULL;
$ch = NULL;
$url = NULL;
}
$url = "url";
$content = get_content($url);
$content_x = explode("<result>", $content);
foreach ($content_x as $item)
{
$p1 = strpos($item, '<title>');
$p2 = strpos($item, '</title>');
$l1 = $p2 - $p1;
echo '<br>'.$title = substr($item, $p1, $l1);
}
xml site feed
<?xml version="1.0" encoding="UTF-8"?>
<response version="2">
<totalpage>1005</totalpage>
<results>
<result>
<title>test</title>
<title2>test2</title2>
<title3>test3</title3>
<result>
<result>
<title>test</title>
<title2>test2</title2>
<title3>test3</title3>
<result>
<result>
<title>test</title>
<title2>test2</title2>
<title3>test3</title3>
<result>
........so on
<results>
</response>
I need to get totalpage and everyting in results
How do get totalpage and is they better way to process the results
You absolutely should not be using string manipulation to try to parse XML. There are any number of PHP libraries that can do this. I might recommend SimpleXML.
Usage would be:
$xml = simplexml_load_string($content);
$totalpage = $xml->response->totalpage;
This is my php code:
<?php
if (array_key_exists("site", $_GET) && $_GET["site"] != "" )
{
$url = $_REQUEST['site'];
$url = " http://api.mywot.com/0.4/public_query2?target=";
$result= $url.urlencode($url);
$process = curl_init($result);
//init curl connection
curl_setopt($process, CURLOPT_HEADER, 0);
curl_setopt($process, CURLOPT_POST, 1);
curl_setopt($process, CURLOPT_RETURNTRANSFER,1);
curl_setopt($process,CURLOPT_CONNECTTIMEOUT,1);
$resp = curl_exec($process);
curl_close($process);
header('Content-Type: text/xml');
$xml = new SimpleXMLElement($resp);
}
?>
Assumed xml:
<?xml version="1.0" encoding="UTF-8"?>
<query target="example.com">
<application name="0" r="89" c="44"/>
<application name="1" r="89" c="46"/>
<application name="2" r="92" c="47"/>
<application name="4" r="93" c="48"/>
</query>
I know how to read this kind of xml file
<Status>
<code>200</code>
<request>geocode</request>
</Status>
$status = (int) $xml->Status->code;
The above xml has repeated tags such as application, how can I read certain ones?
application items will be accessible as an array, example: $xml->application[3]
$x = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
<query target="example.com">
<application name="0" r="89" c="44"/>
<application name="1" r="89" c="46"/>
<application name="2" r="92" c="47"/>
<application name="4" r="93" c="48"/>
</query>');
print_r($x); // View entire XML structure
print_r($x->application[1]); // View the 2nd application item
echo $x->application[1]['c']; // Get 'c' attribute from 2nd item (46)
$xml->application[0];
$xml->application[1];
$xml->application[2];
...
In addition to other answers you can also use XPath to get certain elements from an XML structure:
$xml->xpath('/query/application[#name=2]')
will return the <application> element with attribute name = 2. See w3schools XPath tutorial for more info on conditions. Just keep in mind that XPath is somewhat slow in PHP with SimpleXML, even though you won't notice it unless you have a large document with thousands of elements. It's a good way of seeking not-so-big XMl structures. If you have to deal with large sets you might want to switch to DOMDocument. It isn't as simple and easy to follow but it has much greater performance with XPath.
Update
I see you're trying to parse full response as XMl. But $resp will actually contain FULL response, I mean including headers. Of course it won't parse correctly. What you need to do is:
//...
$resp = curl_exec($process);
$resp = substr( $resp, curl_getinfo($process, CURLINFO_HEADER_SIZE) );
curl_close($process);
//...
I have a problem.
I have 2 php scripts, one which sends xml data using curl and one which is supposed to read the posted data.
The problem is the reciever script is not getting any of the elements in the xml.
Any help would be appriciated.
SENDER SCRIPT:
<?php
$xml = '
<SMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://api.xxxxxxxxxxxxxxx.co.uk/send/xxxxxxxxxxxxxxx.xsd">
<auth>
<user>yourusername</user>
<pass>yourpassword</pass>
</auth>
<originator>your_sender_name</originator>
<messages>
<msg id="1" gsm="440000000000">
<text>Please come for you appointment tomorrow morning at 12:45</text>
</msg>
<msg id="1" gsm="440000000000">
<text>Please come for you appointment tomorrow morning at 14:00</text>
</msg>
</messages>
</SMS>';
function sendMessages($xml) {
$curl = curl_init();
//$url = "https://sapi.xxxxxxxxxxxxxxx.co.uk/send/xml.php";
$url = "http://api.xxxxxxxxxxxxxxx.co.uk/send/xml.php";
$options = array(CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_POSTFIELDS => $xml);
curl_setopt_array($curl, $options);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
echo sendMessages($xml);
//echo $xml;
?>
RECIEVER SCRIPT:
<?php
function logResult() {
$postdata = file_get_contents("php://input");
$dom = new DOMDocument();
$dom->loadXML($postdata);
$xp = new domxpath($dom);
$messages = $xp->query("//SMS/auth");
//var_dump($messages);
foreach ($messages as $node) {
//var_dump($node);
return $node->getAttribute('user');
//$node->getAttribute('sentdate');
//$node->getAttribute('donedate');
}
}
echo logResult();
?>
I was unable to get DOMDocument to even load this XML string, with or without the namespace. I have no idea why.
I'd suggest using SimpleXMLElement. I use it a lot, and it works great. I was also able to get it to parse your XML string.