I have sudo string in a sort of xml format which i want to convert to xml in php. Which I then want to grab the imaware which contains date string in different formats and convert to appropriate date.
sudo string
<IMAware>
09-03-2016 05:28
</IMAware>
<NextUpdate>
</NextUpdate>
<ETR>
</ETR>
<SMS>
text
</SMS>
<Summary>
text
</Summary>
<Impact>
text
</Impact>
<Plan>
</Plan>
<Resolution>
text
</Resolution>
<Complete>
text
</Complete>
<Timeline>
text
</Timeline>
<Crisis>
</Crisis>
So far I have the following
for ($i = 0; $i < count($dbData); $i++) {
try {
print_r(trim($dbData[$i]['INCIDENT_NOTES']));
$xml = simplexml_load_string (trim($dbData[$i]['INCIDENT_NOTES']));
print_r($xml);
} catch (Exception $e) {
echo $e;
}
/*$items = $xml->xpath(item);
foreach($items as $item) {
echo $item['title'], ': ', $item['description'], "\n";
}*/
}
This fails with
Warning: simplexml_load_string(): Entity: line 5: parser error : Extra content at the end of the document in /var/SP/oiadm/docroot/dev/maskella/common/api/Api.class.php on line 1444
Do I need to enclose with<?xml version='1.0'?> <document></document>?
Date formats which I have are
21-02-2016 20:14
Date/Time: 09/02 - 15:40
Date: 08/02 - 11:50
Yes, the xml doc will need the header, and will also need a root element which encapsulates the elements from your sudo example.
See What is the correct format to use for Date/Time in an XML file for appropriate date formats in XML.
Related
I tried to set up app attestation between my app and php but I rarely find any other source of explaination than Apple's own documentation, which let me stuck quite at an early state. So far I got the following steps:
On the client side, following https://developer.apple.com/documentation/devicecheck/establishing_your_app_s_integrity, I creted my attestation as a base64 encoded string:
attestation.base64EncodedString()
I then send that string to the server, following https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server from now on.
The documentation says, that the attestation is in the CBOR format. I therefor first decode the base64 encoded string and parse it using (https://github.com/Spomky-Labs/cbor-php).
<?php
use CBOR\Decoder;
use CBOR\OtherObject;
use CBOR\Tag;
use CBOR\StringStream;
$otherObjectManager = new OtherObject\OtherObjectManager();
$tagManager = new Tag\TagObjectManager();
$decoder = new Decoder($tagManager, $otherObjectManager);
$data = base64_decode(/* .. base64 encoded attestation string as send from the client (see swift snippet above) */);
$stream = new StringStream($data);
$object = $decoder->decode($stream);
$norm = $object->getNormalizedData();
$fmt = $norm['fmt'];
$x5c = $norm['attStmt']['x5c'];
From the documentation, the normalized object should have the following format:
{
fmt: 'apple-appattest',
attStmt: {
x5c: [
<Buffer 30 82 02 cc ... >,
<Buffer 30 82 02 36 ... >
],
receipt: <Buffer 30 80 06 09 ... >
},
authData: <Buffer 21 c9 9e 00 ... >
}
which it does:
$fmt == "apple-appattest" // true
Then the next according to the documentation is described as:
Verify that the x5c array contains the intermediate and leaf certificates for App Attest, starting from the credential certificate in the first data buffer in the array (credcert). Verify the validity of the certificates using Apple’s App Attest root certificate.
However, I don't know how to proceed further on this. The content of e.g. $norm['attStmt']['x5c'][0] is a mix of readable chars and glyphs. To give you an idea, this is a random substring from the content of $norm['attStmt']['x5c'][0]: "Certification Authority10U Apple Inc.10 UUS0Y0*�H�=*�H�=B��c�}�". That's why I'm not really sure wheather I have to perform any further encodeing/decoding steps.
I tried parsing the certificate but without any luck (both var_dump return false):
$cert = openssl_x509_read($x5c[0]);
var_dump($cert); // false - indicating that reading the cert failed
$parsedCert = openssl_x509_parse($cert, false);
var_dump($parsedCert); // false - of course, since the prior step did not succeed
Any ideas, guidance or alternative ressources are highly appreciated. Thank you!
After a while I came up with the following solution. The $x5c field contains a list of certificates, all in binary form. I wrote the folowing converter to create a ready-to-use certificate in PEM format, which does the following:
base64 encode the binary data
break lines after 64 bytes
add BEGIN and END markers (also note the trailing line-break on the end certificate line)
function makeCert($bindata) {
$beginpem = "-----BEGIN CERTIFICATE-----\n";
$endpem = "-----END CERTIFICATE-----\n";
$pem = $beginpem;
$cbenc = base64_encode($bindata);
for($i = 0; $i < strlen($cbenc); $i++) {
$pem .= $cbenc[$i];
if (($i + 1) % 64 == 0)
$pem .= "\n";
}
$pem .= "\n".$endpem;
return $pem;
}
the following then works:
openssl_x509_read(makeCert($x5c[0]))
Back at it again with another XML/PHP problem. :)
On my webpage I want to display the names of the tools provided in the last X days. X is a number that will be entered by the user in a textbox, and after clicking the submit button, the names of the tools that have been provided in those last X days will appear.
This will be done by comparing the X value the user enters with the dates in my XML file, and to find the tools that match.
In my XML file, I have a "dateentered" node that stores a random date that I entered:
<tools>
<tool type="..." web-based="..." free="...">
<name>Facebook</name>
<description>...</description>
<url>...</url>
<subjects>...</subjects>
<creators>...</creators>
<category>...</category>
<price>...</price>
<dateentered>2020-12-01</dateentered>
</tool>
</tools>
Next, I created a function in PHP that basically converts the 'Y-M-D' format into days by subtracting the current date from whatever date you enter:
function time2string($timeline) {
$periods = array('day' => 86400);
$ret = '';
foreach($periods AS $name => $seconds){
$num = floor($timeline / $seconds);
$timeline -= ($num * $seconds);
$ret .= $num;
}
return trim($ret);
}
Then, I loaded my xml file using simpleXML:
$xml = simplexml_load_file('tools.xml');
So for example, using the XML code sample above and doing
$days = $xml->xpath("//tool/dateentered");
foreach ($days as $day) {
print (time2string(time()-strtotime($day)));
}
this converts '2020-12-02' to '1' and therefore outputs '1', meaning that the function works as it should.
With XPath, What I want to do is, I want to compare the value the user enters in the textbox with the converted 'dateentered' from my xml, and if they match, then I want to display the tool name.
So something like:
if(isset($_REQUEST["submit"])) {
// time2string function
$f_day = $_REQUEST["days"]; // getting the value the user enters in the textbox
$xml = simplexml_load_file('tools.xml');
// do something here
}
So let's say, using the xml sample I provided above, if the user enters 1 in the textbox, the output should be:
Facebook
How can I solve this?
I'm also open for different approaches besides having to create a function, this is just what I came up with.
Turns out, like #CBroe has said, I don't even need a function that converts date to days, instead, I can take advantage of PHP's date() and strtotime() functions as follows:
<?php
if(isset($_REQUEST["submit"])) {
$xml = simplexml_load_file('tools.xml');
$f_days = $_REQUEST["days"];
$days = date("Y-m-d", strtotime("-$f_days days"));
$xdays = $xml->xpath("//tool[dateentered = '$days']/name");
foreach ($xdays as $name) {
echo "<h1 align='center'>".$name."</h1><br>";
}
}
?>
And this will output:
Facebook
I have searched for solution for this problem but none fix my problem.
The answers suggest that I use isset to check the array before working on it. But I will explain how it doesnt do it for me later.
Pre-req:
I've got a huge XML file from a tour & travel webservice which I would parse and convert to PHP array and later do some operation on it. (Filter tours mostly).
My Approach:
I'm using SimpleXML to load the xml and convert it to PHP array like so:
$xml = file_get_contents(APPPATH."tour.xml", true);
$xmlString = htmlentity_to_xml($xml); //custom method to clean XML
$Str = simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOCDATA);
//converting to array
$json = json_encode($Str);
$array = json_decode($json,TRUE);
Then I'm sending this array to a fitlerTours($searchParams, $tourArray) method along with search parameters (cityName & dates) and the array itself.
Then using foreach() i'm going through each tour to look for the cityName and raising a flag if found.
The Problem
When I filter the tours (the ones which contain cityName) for dates, I'm getting this.
Severity: Warning
Message: Illegal string offset 'year'
Filename: controllers/tourFilter.php
Line Number: 78
Warning shows for offeset 'month' and 'day' also.
Here's my PHP for date filter: (Line 78 is 4th line)
if($flag == 1){
if(!empty($fromDate)){
foreach($tour['departureDates']['date'] AS $date){
$dateDep = strtotime($date['year'] . "-" . (($date['month']) < 10 ? "0".$date['month'] : $date['month']) . "-" . (($date['day']) < 10 ? "0".$date['day'] : $date['day']));
if(strtotime($fromDate) <= $dateDep && $dateDep <= strtotime($fromDate . "+".$range." days")){
if($date['departureStatus'] != "SoldOut"){
$dateFlag = 1;
}
}
}
}
else{
$dateFlag = 1;
}
$flag = 0;
}
if($dateFlag == 1){//Collect tours which contain the keyword & dates to $response array
$responseArray[] = $tour;
$dateFlag = false; //Reset Flag
}
Here's the snippet of XML:
...
<departureDates>
<date>
<day>7</day>
<month>1</month>
<year>2016</year>
<singlesPrice>12761</singlesPrice>
<doublesPrice>9990</doublesPrice>
<triplesPrice>0</triplesPrice>
<quadsPrice>0</quadsPrice>
<shipName/>
<departureStatus>Available</departureStatus>
</date>
<date>
<day>8</day>
<month>1</month>
<year>2016</year>
<singlesPrice>12761</singlesPrice>
<doublesPrice>9990</doublesPrice>
<triplesPrice>0</triplesPrice>
<quadsPrice>0</quadsPrice>
<shipName/>
<departureStatus>SoldOut</departureStatus>
</date>
</departureDates>
...
Now if i use the solution I found by searching around is check if the array is set properly by isset() it doesn't return true and line 78 is not executed and the data is lost. But I need the data.
This happens for only keywords i search.
Any help is appreciated.
The error says that the $date var is detected as string in some point...
Characters within strings may be accessed and modified by specifying
the zero-based offset of the desired character after the string using
square array brackets, as in $str[42]. Think of a string as an array
of characters for this purpose.
See here
So try this:
if(is_array($date)){
$dateDep = strtotime($date['year'] . "-" . (($date['month']) < 10 ? "0".$date['month'] : $date['month']) . "-" . (($date['day']) < 10 ? "0".$date['day'] : $date['day']));
if(strtotime($fromDate) <= $dateDep && $dateDep <= strtotime($fromDate . "+".$range." days")){
if($date['departureStatus'] != "SoldOut"){
$dateFlag = 1;
}
}
}
else {
//If this is not an array what is it then?
var_dump($date);
}
Following is my code which I am using for testing purposes so far. I have to use it further in my project.
It access a certain web service and retrieves data as xml. XML is brought to $arr array.
Address of $url and 3rd parameter in client->call() are not mentioned on purpose.
$url = "";
$client= new nusoap_client($url);
$param = array("status"=>"p2");
$arr = $client->call('getAllVisitByStatus',$param,'');
echo $arr."\n";
$size = sizeof($arr);
echo $size;
for($num=0; $num<986; ++$num)
{
echo $arr[$num], "\n";
if($arr[$num] == '>')
{
echo "<br/> ";
}
}
If I save the data returned by client->call() into an array and print it with a loop then it prints the XML like this
<?xml version = "1.0" encoding = "UTF - 8" standalone = "yes" ?>
<lists>
<visitW>
<followup> 2015 - 01 - 30 00:50:00.0 </followup>
<person_id> 12 </person_id>
<remarks> nothing </remarks>
<treatment> doing </treatment>
<visit_date> 2015 - 01 - 04 - 00 - 24 - </visit_date>
<visit_id> 4 </visit_id>
<visit_type> Hesschart</visit_type>
</visitW>
</lists>
However, if take $arr as a string, it prints this:
2015-01-30 00:50:00.0 12 nothing doing 2015-01-04-00-24- 4 Hesschart
So, in a string it prints without tags and like this.
The problem is that when the size of array is printed, it prints 1. However, the array contains the whole XML brought as a result of service call.
When I use a loop of exact number of elements i.e. 986, then it prints the whole XML as it is.
The question is that why does it show 1 as the size of the array? Also, can this array containing XML be put in DOM Parser?
I am trying to create a PHP script to get the app version from Android APK file.
Extracting XML file from the APK (zip) file and then parsing XML is one way, but I guess it should be simpler. Something like PHP Manual, example #3.
Any ideas how to create the script?
If you have the Android SDK installed on the server, you can use PHP's exec (or similar) to execute the aapt tool (in $ANDROID_HOME/platforms/android-X/tools).
$ aapt dump badging myapp.apk
And the output should include:
package: name='com.example.myapp' versionCode='1530' versionName='1.5.3'
If you can't install the Android SDK, for whatever reason, then you will need to parse Android's binary XML format. The AndroidManifest.xml file inside the APK zip structure is not plain text.
You would need to port a utility like AXMLParser from Java to PHP.
I've created a set of PHP functions that will find just the Version Code of an APK. This is based on the fact that the AndroidMainfest.xml file contains the version code as the first tag, and based on the axml (binary Android XML format) as described here
<?php
$APKLocation = "PATH TO APK GOES HERE";
$versionCode = getVersionCodeFromAPK($APKLocation);
echo $versionCode;
//Based on the fact that the Version Code is the first tag in the AndroidManifest.xml file, this will return its value
//PHP implementation based on the AXML format described here: https://stackoverflow.com/questions/2097813/how-to-parse-the-androidmanifest-xml-file-inside-an-apk-package/14814245#14814245
function getVersionCodeFromAPK($APKLocation) {
$versionCode = "N/A";
//AXML LEW 32-bit word (hex) for a start tag
$XMLStartTag = "00100102";
//APK is esentially a zip file, so open it
$zip = zip_open($APKLocation);
if ($zip) {
while ($zip_entry = zip_read($zip)) {
//Look for the AndroidManifest.xml file in the APK root directory
if (zip_entry_name($zip_entry) == "AndroidManifest.xml") {
//Get the contents of the file in hex format
$axml = getHex($zip, $zip_entry);
//Convert AXML hex file into an array of 32-bit words
$axmlArr = convert2wordArray($axml);
//Convert AXML 32-bit word array into Little Endian format 32-bit word array
$axmlArr = convert2LEWwordArray($axmlArr);
//Get first AXML open tag word index
$firstStartTagword = findWord($axmlArr, $XMLStartTag);
//The version code is 13 words after the first open tag word
$versionCode = intval($axmlArr[$firstStartTagword + 13], 16);
break;
}
}
}
zip_close($zip);
return $versionCode;
}
//Get the contents of the file in hex format
function getHex($zip, $zip_entry) {
if (zip_entry_open($zip, $zip_entry, 'r')) {
$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
$hex = unpack("H*", $buf);
return current($hex);
}
}
//Given a hex byte stream, return an array of words
function convert2wordArray($hex) {
$wordArr = array();
$numwords = strlen($hex)/8;
for ($i = 0; $i < $numwords; $i++)
$wordArr[] = substr($hex, $i * 8, 8);
return $wordArr;
}
//Given an array of words, convert them to Little Endian format (LSB first)
function convert2LEWwordArray($wordArr) {
$LEWArr = array();
foreach($wordArr as $word) {
$LEWword = "";
for ($i = 0; $i < strlen($word)/2; $i++)
$LEWword .= substr($word, (strlen($word) - ($i*2) - 2), 2);
$LEWArr[] = $LEWword;
}
return $LEWArr;
}
//Find a word in the word array and return its index value
function findWord($wordArr, $wordToFind) {
$currentword = 0;
foreach ($wordArr as $word) {
if ($word == $wordToFind)
return $currentword;
else
$currentword++;
}
}
?>
Use this in the CLI:
apktool if 1.apk
aapt dump badging 1.apk
You can use these commands in PHP using exec or shell_exec.
aapt dump badging ./apkfile.apk | grep sdkVersion -i
You will get a human readable form.
sdkVersion:'14'
targetSdkVersion:'14'
Just look for aapt in your system if you have Android SDK installed.
Mine is in:
<SDKPATH>/build-tools/19.0.3/aapt
The dump format is a little odd and not the easiest to work with. Just to expand on some of the other answers, this is a shell script that I am using to parse out name and version from APK files.
aapt d badging PACKAGE | gawk $'match($0, /^application-label:\'([^\']*)\'/, a) { n = a[1] }
match($0, /versionName=\'([^\']*)\'/, b) { v=b[1] }
END { if ( length(n)>0 && length(v)>0 ) { print n, v } }'
If you just want the version then obviously it can be much simpler.
aapt d badging PACKAGE | gawk $'match($0, /versionName=\'([^\']*)\'/, v) { print v[1] }'
Here are variations suitable for both gawk and mawk (a little less durable in case the dump format changes but should be fine):
aapt d badging PACKAGE | mawk -F\' '$1 ~ /^application-label:$/ { n=$2 }
$5 ~ /^ versionName=$/ { v=$6 }
END{ if ( length(n)>0 && length(v)>0 ) { print n, v } }'
aapt d badging PACKAGE | mawk -F\' '$5 ~ /^ versionName=$/ { print $6 }'