How to use loop in comment section - php

I have used foreach loop to extract multiple value of user_phone between tab but it will produce error.I dont what is exact formate.
$result = $Admin->select($Admin->newsletter_subscribers,'',"");
print_r($result['user_phone']);
$data="<message-submit-request>
<username>#######</username>
<password>#######</password>
<sender-id>$$$$$$</sender-id>".
foreach($result as $row)
{
"<to>".$row['user_phone']."</to>"
}."<MType></MType>
<message-text>
<text>hi test message 1</text>
</message-text>
</message-submit-request>";

Try this:
$result = $Admin->select($Admin->newsletter_subscribers,'',"");
print_r($result['user_phone']);
$data = "<message-submit-request>
<username>#######</username>
<password>#######</password>
<sender-id>$$$$$$</sender-id>";
foreach($result as $row)
{
$data .= "<to>".$row['user_phone']."</to>";
}
$data .= "<MType></MType>
<message-text>
<text>hi test message 1</text>
</message-text>
</message-submit-request>";

The exact format for string concatenation is shown in the PHP manual under string operators. However I won't elaborate on these directly becasue cerating XML by concatenating strings is a bad idea. For example having characters like <, > and & in your input, you'll run into many problems.
For your use-case SimpleXMLElement is a handy object that allows you to do the same in a much more consisted manner:
// create XML document based on boilerplate
$xml = new SimpleXMLElement('
<message-submit-request>
<username>#######</username>
<password>#######</password>
<sender-id>$$$$$$</sender-id>
<MType></MType>
<message-text>
<text>hi test message 1</text>
</message-text>
</message-submit-request>
');
// add elements where appropriate
foreach($result as $row)
{
$xml->addChild('to', $row['user_phone']);
}
This will ensure that all values are properly encoded. Additionally this can have a magnitude on benefits when you further process the data, e.g. outputting it.
However you haven't shown in your question what follows up with $data so you need to know how to obtain the XML from the SimpleXMLElement as string to make the example complete. Here it is:
$data = $xml->asXML();
See as well the SimpleXML Basic Usage guide in the manual if you'd like to learn more.

Related

Unable to produce variable output of type string in multi-lines in PHP

I don't know the correct wording for this issue I am having.
I have a object returned from the database like below:
$pProvisioningFileData->m_fileContent = # Placeholders identified by '${}'
will be replaced during the provisioning
# process, only supported placeholders will be processed.
Dcm.SerialNumber = ${unit.serial_number}
Dcm.MacAddress = ${unit.mac_address}
Dcm.MinSeverity = "Warning"
Cert.TransferHttpsCipherSuite = "CS1"
Cert.TransferHttpsTlsVersion = "TLSv1"
Cert.MinSeverity = "Warning";
The curly brackets are placeholders, the problem I am facing is that when I try output all the content using either echo or print_r, all the content prints in one line however I want to display the content in the same sequence as above.
I tried using var_dump but it also gives some extra info like length and type of variable which I don't want.
So is there a simple way of doing this without using an array?
If you are outputting to browser then wrapping your var_dump in html <pre> tags is quick solution. If you outputting to console then I advise you to install some advanced debuging software. Xdebug comes to mind.
It is difficult from your question to understand exactly what you are wanting to do, but there are three ways you can print out the contents of an object. The third here, looping members, will give you more control and you can add a switch statement or other formatting to output precisely what you desire:
class unit {
var $serial_number;
var $mac_address;
}
$test = new unit;
$test->serial_number = "999";
$test->mac_address = "999.999.999.999";
/* Method 1 - print_r */
print_r($test);
print "\n\n";
/* Method 1 - var_dump */
var_dump($test);
print "\n\n";
/* Method 3 - looping members */
foreach ($test as $memberName => $member)
{
print "{$memberName}: {$member}\n";
}

Get XML tags from asXML()

I am parsing through an XML document and getting the values of nested tags using asXML(). This works fine, but I would like to move this data into a MySQL database whose columns match the tags of the file. So essentially how do I get the tags that asXML() is pulling text from?
This way I can eventually do something like: INSERT INTO db.table (TheXMLTag) VALUES ('XMLTagText');
This is my code as of now:
$xml = simplexml_load_file($target_file) or die ("Error: Cannot create object");
foreach ($xml->Message->SettlementReport->SettlementData as $main ){
$value = $main->asXML();
echo '<pre>'; echo $value; echo '</pre>';
}
foreach ($xml->Message->SettlementReport->Order as $main ){
$value = $main->asXML();
echo '<pre>'; echo $value; echo '</pre>';
}
This is what my file looks like to give you an idea (So essentially how do I get the tags within [SettlementData], [0], [Fulfillment], [Item], etc. ?):
I would like to move this data into a MySQL database whose columns match the tags of the file.
Your problem is two folded.
The first part of the problem is to do the introspection on the database structure. That is, obtain all table names and obtain the column names of these. Most modern databases offer this functionality, so does MySQL. In MySQL those are the INFORMATION_SCHEMA Tables. You can query them as if those were normal database tables. I generally recommend PDO for that in PHP, mysqli is naturally doing the job perfectly as well.
The second part is parsing the XML data and mapping it's data onto the database tables (you use SimpleXMLElement for that in your question so I related to it specifically). For that you first of all need to find out how you would like to map the data from the XML onto the database. An XML file does not have a 2D structure like a relational database table, but it has a tree structure.
For example (if I read your question right) you identify Message->SettlementReport->SettlementData as the first "table". For that specific example it is easy as the <SettlementData> only has child-elements that could represent a column name (the element name) and value (the text-content). For that it is easy:
header('Content-Type: text/plain; charset=utf-8');
$table = $xml->Message->SettlementReport->SettlementData;
foreach ($table as $name => $value ) {
echo $name, ': ', $value, "\n";
}
As you can see, specifying the key assignment in the foreach clause will give you the element name with SimpleXMLElement. Alternatively, the SimpleXMLElement::getName() method does the same (just an example which does the same just with slightly different code):
header('Content-Type: text/plain; charset=utf-8');
$table = $xml->Message->SettlementReport->SettlementData;
foreach ($table as $value) {
$name = $value->getName();
echo $name, ': ', $value, "\n";
}
In this case you benefit from the fact that the Iterator provided in the foreach of the SimpleXMLElement you access via $xml->...->SettlementData traverses all child-elements.
A more generic concept would be Xpath here. So bear with me presenting you a third example which - again - does a similar output:
header('Content-Type: text/plain; charset=utf-8');
$rows = $xml->xpath('/*/Message/SettlementReport/SettlementData');
foreach ($rows as $row) {
foreach ($row as $column) {
$name = $column->getName();
$value = (string) $column;
echo $name, ': ', $value, "\n";
}
}
However, as mentioned earlier, mapping a tree-structure (N-Depth) onto a 2D-structure (a database table) might now always be that straight forward.
If you're looking what could be an outcome (there will most often be data-loss or data-duplication) a more complex PHP example is given in a previous Q&A:
How excel reads XML file?
PHP XML to dynamic table
Please note: As the matter of fact such mappings on it's own can be complex, the questions and answers inherit from that complexity. This first of all means those might not be easy to read but also - perhaps more prominently - might just not apply to your question. Those are merely to broaden your view and provide and some examples for certain scenarios.
I hope this is helpful, please provide any feedback in form of comments below. Your problem might or might not be less problematic, so this hopefully helps you to decide how/where to go on.
I tried with SimpleXML but it skips text data. However, using the Document Object Model extension works.
This returns an array where each element is an array with 2 keys: tag and text, returned in the order in which the tree is walked.
<?php
// recursive, pass by reference (spare memory ? meh...)
// can skip non tag elements (removes lots of empty elements)
function tagData(&$node, $skipNonTag=false) {
// get function name, allows to rename function without too much work
$self = __FUNCTION__;
// init
$out = array();
$innerXML = '';
// get document
$doc = $node->nodeName == '#document'
? $node
: $node->ownerDocument;
// current tag
// we use a reference to innerXML to fill it later to keep the tree order
// without ref, this would go after the loop, children would appear first
// not really important but we never know
if(!(mb_substr($node->nodeName,0,1) == '#' && $skipNonTag)) {
$out[] = array(
'tag' => $node->nodeName,
'text' => &$innerXML,
);
}
// build current innerXML and process children
// check for children
if($node->hasChildNodes()) {
// process children
foreach($node->childNodes as $child) {
// build current innerXML
$innerXML .= $doc->saveXML($child);
// repeat process with children
$out = array_merge($out, $self($child, $skipNonTag));
}
}
// return current + children
return $out;
}
$xml = new DOMDocument();
$xml->load($target_file) or die ("Error: Cannot load xml");
$tags = tagData($xml, true);
//print_r($tags);
?>

PHP script converting XML to CSV with column headers returning blank on some headers and rows

my full XML is below which is named user.xml:
<?xml version="1.0" encoding="utf-8"?>
<users>
<user id='1'>
<user_name>John</user_name>
<user_lastname>Doe</user_lastname>
<previous_requisitions>
<requisition_code>X321</requisition_code>
<requisition_code>Y321</requisition_code>
<requisition_code>Z321</requisition_code>
</previous_requisitions>
<user_requisition>
<requisition_code>X123</requisition_code>
<requisition_title>Ssr Dev 1</requisition_title>
<requisition_relocation>10~20%</requisition_relocation>
</user_requisition>
</user>
<user id='2'>
<user_name>James</user_name>
<user_lastname>Smith</user_lastname>
<previous_requisitions>
<requisition_code>X222</requisition_code>
<requisition_code>Y222</requisition_code>
<requisition_code>Z222</requisition_code>
</previous_requisitions>
<user_requisition>
<requisition_code>Y123</requisition_code>
<requisition_title>Sr Dev 1</requisition_title>
<requisition_relocation>20~30%</requisition_relocation>
</user_requisition>
</user>
<user id='3'>
<user_name>Jess</user_name>
<user_lastname>Ssej</user_lastname>
<previous_requisitions>
<requisition_code>X111</requisition_code>
<requisition_code>Y111</requisition_code>
<requisition_code>Z111</requisition_code>
</previous_requisitions>
<user_requisition>
<requisition_code>Z123</requisition_code>
<requisition_title>Jr Dev 2</requisition_title>
<requisition_relocation>0~10%</requisition_relocation>
</user_requisition>
</user>
</users>
since not very good with XML and with the help of online resources and stackoverflow; was able to create this PHP script:
<?php
$file='user.xml';
if (file_exists($file)) {
$xml = simplexml_load_file($file);
$f = fopen('user.csv', 'w');
// array to hold the field names
$headers = array();
// loop through the first set of fields to get names
foreach ($xml->user->children() as $field) {
// put the field name into array
$headers[] = $field->getName();
}
// print headers to CSV
fputcsv($f, $headers, ',', '"');
foreach ($xml->user as $users) {
fputcsv($f, get_object_vars($users), ',', '"');
}
fclose($f);
}
?>
when i run the PHP script, the file is written but with some issues:
not all headers are written.
not all data are written
first column is populated with "Array"
see below for screenshot of the result(open in excel):
QUESTIONS:
since it appears that the $headers = array(); is not looping properly. any fix on the PHP script to show all headers and the data from the XML properly?
i only need the following child nodes to be exported to CSV, so these 6 will also be the headers:
user_id,
user_name,
user_lastname,
user_requisition_code,
user_requisition_title,
user_requisition_relocation,
pls direct me how i can make the script "selective" in which omitting or not to include other child nodes from the XML like:
previous_requisitions
requisition_code
is there a way for PHP(without using BASH, wk or sed) to work or write a "pipe delimited file" instead of CSV from XML assuming to use the same XML file above given. i tried replacing the comma in the script for a PIPE character and browser output gives me this warning:
Warning: fputcsv() expects parameter 1 to be resource, boolean
thanks a lot for the help and happy new year!
sidenote: would be sticking with opensource scripting hoping no one will answer with suggestion to use a proprietary software.
For 1.) it might appear to you that $headers = array(); is not looping properly, but I don't see anything wrong with the looping. It's perfectly fine and absolutely follows what is documented with SimpleXML: http://php.net/book.simplexml .
For 2.) I'd say you want to skip all same-named elements within a grouping element (if any). This somewhat reminds me to this question and answer but in that example, siblings with the same name and the same parent were interpolated into additional rows. In your case you just want to skip them.
For you perhaps easier is to just query via xpath the values you're looking for. As the elements you query also have a name which is even the column name, this should work quite well, too. (I will show both variants in example codes below)
For 3.) this should be perfectly well possible. The error message you give makes it look to me you confused some other parameters. It's not related to setting pipe as a delimiter (the code examples will use the pipe symbol "|" as CSV delimiter, it perfectly works).
That being said, a solution that comes close to what you visually outlined in the question (but is missing the user id) could be:
$csv = new SplFileObject('php://output', 'w');
$csv->setCsvControl("|");
$users = iterator_to_array($xml->user, false);
foreach ($users as $index => $user) {
$fields = [];
foreach ($user->xpath('(*[not(./*)]|user_requisition/*)') as $field) {
$fields[$field->getName()] = trim($field);
}
// first iteration output headers
$index || $csv->fputcsv(array_keys($fields));
$csv->fputcsv($fields);
}
The exemplary output with your example XML is:
user_name|user_lastname|requisition_code|requisition_title|requisition_relocation
John|Doe|X123|"Ssr Dev 1"|10~20%
James|Smith|Y123|"Sr Dev 1"|20~30%
Jess|Ssej|Z123|"Jr Dev 2"|0~10%
The use-case with the mapping would be a slightly different code:
$csv = new SplFileObject('php://output', 'w');
$csv->setCsvControl("|");
$fieldDefs = [
'user_id' => '#id',
'user_name' => 'user_name',
'user_lastname' => 'user_lastname',
'requisition_code' => 'user_requisition/requisition_code',
'requisition_title' => 'user_requisition/requisition_title',
'requisition_relocation' => 'user_requisition/requisition_relocation',
];
// output CSV headers
$csv->fputcsv(array_keys($fieldDefs));
$users = $xml->user;
foreach ($users as $user) {
$fields = [];
foreach ($fieldDefs as $fieldDef) {
$fields[] = $user->xpath($fieldDef)[0];
}
$csv->fputcsv($fields);
}
With a slightly different output:
user_id|user_name|user_lastname|requisition_code|requisition_title|requisition_relocation
1|John|Doe|X123|"Ssr Dev 1"|10~20%
2|James|Smith|Y123|"Sr Dev 1"|20~30%
3|Jess|Ssej|Z123|"Jr Dev 2"|0~10%
This second example shows how to combine a more concrete mapping to the headers. This is a bit more explicit and allows to name the headers differently from the element names.
I hope these examples are quite self-explanatory, but you might stumble over some things I do differently to what you might have done. E.g. I use SplFileObject to do the CSV operations, it's basically really the same as the method you use, however in form of an object which keeps the code a bit more clean (as there is no need to repeat some of the parameters).
The XPath expressions in the second example as well might be new to you, but I hope they are really self explanatory just from looking at the array and the XML you've been given.
The examples should be backwards compatible down to PHP 5.4.

Ampersands in database

I am trying to write a php function that goes to my database and pulls a list of URLS and arranges them into an xml structure and creates an xml file.
Problem is, Some of these urls will contain an ampersand that ARE HTML encoded. So, the database is good, but currently, when my function tries to grab these URLS, the script will stop at the ampersands and not finish.
One example link from database:
http://www.mysite.com/myfile.php?select=on&league_id=8&sport=15
function buildXML($con) {
//build xml file
$sql = "SELECT * FROM url_links";
$res = mysql_query($sql,$con);
$gameArray = array ();
while ($row = mysql_fetch_array($res))
{
array_push($row['form_link']);
}
$xml = '<?xml version="1.0" encoding="utf-8"?><channel>';
foreach ($gameArray as $link)
{
$xml .= "<item><link>".$link."</link></item>";
}
$xml .= '</channel>';
file_put_contents('../xml/full_rankings.xml',$xml);
}
mysql_close($con);
session_write_close();
If i need to alter the links in the database, that can be done.
You can use PHP's html_entity_decode() on the $link to convert & back to &.
In your XML, you could also wrap the link in <![CDATA[]]> to allow it to contain the characters.
$xml .= "<item><link><![CDATA[" . html_entity_decode($link) . "]]></link></item>";
UPDATE
Just noticed you're actually not putting anything into the $gameArray:
array_push($row['form_link']);
Try:
$gameArray[] = $row['form_link'];
* #Musa looks to have noticed it first, for due credit.
Look at this line
array_push($row['form_link']);
you never put anything in the $gameArray array, it should be
array_push($gameArray, $row['form_link']);
You need to use htmlspecialchars_decode. It will decode any encoded special characters in string passed to it.
This is most likely what you are looking for:
http://www.php.net/manual/en/function.mysql-real-escape-string.php
Read the documentation, there are examples at the bottom of the page...
'&' in oracleSQL and MySQL are used in queries as a logical operator which is why it is tossing an error.
You may also want to decode the HTML...

Parsing XML with PHP (simplexml)

Firstly, may I point out that I am a newcomer to all things PHP so apologies if anything here is unclear and I'm afraid the more layman the response the better. I've been having real trouble parsing an xml file in to php to then populate an HTML table for my website. At the moment, I have been able to get the full xml feed in to a string which I can then echo and view and all seems well. I then thought I would be able to use simplexml to pick out specific elements and print their content but have been unable to do this.
The xml feed will be constantly changing (structure remaining the same) and is in compressed format. From various sources I've identified the following commands to get my feed in to the right format within a string although I am still unable to print specific elements. I've tried every combination without any luck and suspect I may be barking up the wrong tree. Could someone please point me in the right direction?!
$file = fopen("compress.zlib://$url", 'r');
$xmlstr = file_get_contents($url);
$xml = new SimpleXMLElement($url,null,true);
foreach($xml as $name) {
echo "{$name->awCat}\r\n";
}
Many, many thanks in advance,
Chris
PS The actual feed
Since no one followed my closevote, I think I can just as well put my own comments as an answer:
First of all, SimpleXml can load URIs directly and it can do so with stream wrappers, so your three calls in the beginning can be shortened to (note that you are not using $file at all)
$merchantProductFeed = new SimpleXMLElement("compress.zlib://$url", null, TRUE);
To get the values you can either use the implicit SimpleXml API and drill down to the wanted elements (like shown multiple times elsewhere on the site):
foreach ($merchantProductFeed->merchant->prod as $prod) {
echo $prod->cat->awCat , PHP_EOL;
}
or you can use an XPath query to get at the wanted elements directly
$xml = new SimpleXMLElement("compress.zlib://$url", null, TRUE);
foreach ($xml->xpath('/merchantProductFeed/merchant/prod/cat/awCat') as $awCat) {
echo $awCat, PHP_EOL;
}
Live Demo
Note that fetching all $awCat elements from the source XML is rather pointless though, because all of them have "Bodycare & Fitness" for value. Of course you can also mix XPath and the implict API and just fetch the prod elements and then drill down to the various children of them.
Using XPath should be somewhat faster than iterating over the SimpleXmlElement object graph. Though it should be noted that the difference is in an neglectable area (read 0.000x vs 0.000y) for your feed. Still, if you plan to do more XML work, it pays off to familiarize yourself with XPath, because it's quite powerful. Think of it as SQL for XML.
For additional examples see
A simple program to CRUD node and node values of xml file and
PHP Manual - SimpleXml Basic Examples
Try this...
$url = "http://datafeed.api.productserve.com/datafeed/download/apikey/58bc4442611e03a13eca07d83607f851/cid/97,98,142,144,146,129,595,539,147,149,613,626,135,163,168,159,169,161,167,170,137,171,548,174,183,178,179,175,172,623,139,614,189,194,141,205,198,206,203,208,199,204,201,61,62,72,73,71,74,75,76,77,78,79,63,80,82,64,83,84,85,65,86,87,88,90,89,91,67,92,94,33,54,53,57,58,52,603,60,56,66,128,130,133,212,207,209,210,211,68,69,213,216,217,218,219,220,221,223,70,224,225,226,227,228,229,4,5,10,11,537,13,19,15,14,18,6,551,20,21,22,23,24,25,26,7,30,29,32,619,34,8,35,618,40,38,42,43,9,45,46,651,47,49,50,634,230,231,538,235,550,240,239,241,556,245,244,242,521,576,575,577,579,281,283,554,285,555,303,304,286,282,287,288,173,193,637,639,640,642,643,644,641,650,177,379,648,181,645,384,387,646,598,611,391,393,647,395,631,602,570,600,405,187,411,412,413,414,415,416,649,418,419,420,99,100,101,107,110,111,113,114,115,116,118,121,122,127,581,624,123,594,125,421,604,599,422,530,434,532,428,474,475,476,477,423,608,437,438,440,441,442,444,446,447,607,424,451,448,453,449,452,450,425,455,457,459,460,456,458,426,616,463,464,465,466,467,427,625,597,473,469,617,470,429,430,615,483,484,485,487,488,529,596,431,432,489,490,361,633,362,366,367,368,371,369,363,372,373,374,377,375,536,535,364,378,380,381,365,383,385,386,390,392,394,396,397,399,402,404,406,407,540,542,544,546,547,246,558,247,252,559,255,248,256,265,259,632,260,261,262,557,249,266,267,268,269,612,251,277,250,272,270,271,273,561,560,347,348,354,350,352,349,355,356,357,358,359,360,586,590,592,588,591,589,328,629,330,338,493,635,495,507,563,564,567,569,568/mid/2891/columns/merchant_id,merchant_name,aw_product_id,merchant_product_id,product_name,description,category_id,category_name,merchant_category,aw_deep_link,aw_image_url,search_price,delivery_cost,merchant_deep_link,merchant_image_url/format/xml/compression/gzip/";
$zd = gzopen($url, "r");
$data = gzread($zd, 1000000);
gzclose($zd);
if ($data !== false) {
$xml = simplexml_load_string($data);
foreach ($xml->merchant->prod as $pr) {
echo $pr->cat->awCat . "<br>";
}
}
<?php
$xmlstr = file_get_contents("compress.zlib://$url");
$xml = simplexml_load_string($xmlstr);
// you can transverse the xml tree however you want
foreach ($xml->merchant->prod as $line) {
// $line->cat->awCat -> you can use this
}
more information here
Use print_r($xml) to see the structure of the parsed XML feed.
Then it becomes obvious how you would traverse it:
foreach ($xml->merchant->prod as $prod) {
print $prod->pId;
print $prod->text->name;
print $prod->cat->awCat; # <-- which is what you wanted
print $prod->price->buynow;
}
$url = 'you url here';
$f = gzopen ($url, 'r');
$xml = new SimpleXMLElement (fread ($f, 1000000));
foreach($xml->xpath ('//prod') as $name)
{
echo (string) $name->cat->awCatId, "\r\n";
}

Categories