String parsing error while writing an xml file in php - php

I am writing an sitemap file with php code.I am able to write the file correctly according to requirement.But i want to add namespace tag to starting node of xml file,I tried it doing by the code.But got following error
Uncaught exception Exception with message 'String could not be parsed as XML'
following is my xml structure
<urlset>
<url>
<loc>url1</loc>
</url>
..
..
</urlset>
There are number of url fragments under the parent node as urlset.I want to add namespace tag for sitemaps to urlset node.Thats the only thing i am not able to.Xml file is quite bigger,i am not able to do it manually..
following is my xml formation code
<?php
//Create Database connection
$mysqli = new mysqli('localhost', 'user', 'pass', 'dbname');
if(mysqli_connect_errno()) {
echo "Connection Failed: " . mysqli_connect_errno();
}
/* if (!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
printf("Current character set: %s\n", $mysqli->character_set_name());
}
*/
$xml = new SimpleXMLElement('<xml/>');
for ($i = 0; $i < 2; $i++) {
// used to be: $query='select tablecolname1 from tablename limit 10000';
$start = $i * 50000;
$query = "select Siteurl from tablename limit $start, 50000";
$result = mysqli_query($mysqli,$query);
//Create SimpleXMLElement object
$xml = new SimpleXMLElement('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
while($row = mysqli_fetch_array($result)) {
$mydata = $xml->addChild('url');
$mydata->loc=$row['Siteurl'];
//htmlentities(strip_tags($mydata->loc=$row['Siteurl']), ENT_COMPAT,'utf-8');
}
// used to be: $fp = fopen("folder/file2.xml","wb");
$fp = fopen("site/sitemap$i.xml","wb");
fwrite($fp,utf8_encode($xml->asXML()));
fclose($fp);
}
$xml = new SimpleXMLElement('<urlset/>');
?>
Please guide me on how to add namespace tag to urlset tag..

SimpleXMLElement expects as parameter "a well-formed XML string" according to the documentation.
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' is not such a string.
You can build a XML from PHP in (at least) two (simple) ways:
either only by echoing the content you want in your XML file (tags included):
header('Content-Type:text/xml');
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<urlset xmlns="...">';
...
echo '</urlset>';
or by using the SimpleXML object and building the DOM tree (see example #10 in documentation):
header('Content-Type:text/xml');
$xml=new SImpleXMLElement('<xml/>');
$urlset=$xml->addChild('urlset');
$urlset->addAttribute('xmlns','...');
...
echo $xml->asXML();

Related

PHP mysql - Generating a sitemaps without exceeding 50k rows limit

I have the follwing PHP / MYSQL sitemap that generates a sitemap into the browser. How can i make it save itself to a file and split on 50.000 ? i cant get it to work properly as the script just outputs into plain text. I want the script to output into a file
currently
<?
$xmlfile = 'sitemap.xml';
// this variable will contain the XML sitemap that will be saved in $xmlfile
$xmlsitemap = '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// Connection data (server_address, name, password, database_name)
$hostdb = '';
$userdb = '';
$passdb = '';
$namedb = '';
try {
// Connect and create the PDO object
$conn = new PDO("mysql:host=$hostdb; dbname=$namedb", $userdb, $passdb);
$conn->exec("SET CHARACTER SET utf8"); // Sets encoding UTF-8
// Define and perform the SQL SELECT query
$sql = "SELECT `shortUrl` FROM `shorturl`";
$result = $conn->query($sql);
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach($result as $row) {
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
}
$conn = null; // Disconnect
}
catch(PDOException $e) {
echo $e->getMessage();
}
$xmlsitemap .= '</urlset>';
file_put_contents($xmlfile, $xmlsitemap); // saves the sitemap on server
// outputs the sitemap (delete this instruction if you not want to display the sitemap in browser)
echo $xmlsitemap;
?>
Let's take a look at the code that generating url records..
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
As above, one record contains 5 rows. So your array must contains max 10.000 records right ?
If we split our array into the chunks which contains max 10.000 records, we can easily save each chunk records in different files.
try {
// connect db and get records
# give attention here
$chunks = array_chunk($result, 10000)
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach ($chunks as $key => $chunk) {
$xmlsitemap .= '</urlset $namespaces>';
foreach ($chunk as $row){
$xmlsitemap .= '
<url>
<loc>' . $row['shortUrl'] . '</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
$xmlsitemap .= '</urlset>';
file_put_contents("path/to/directory/sitemap-".$key.".xml", $xmlsitemap);
}
}
}
// check errors
Btw don't forget to create sitemap index for those
Welcome to StackOverflow.
Simply run a counter in your foreach and break it to your desired value.
Not tested code is below
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
$counter = 0;
foreach($result as $row) {
$counter++
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
if($counter==4900){
break;
}
}
}

Differences between two xml strings using php

I'm trying to compare and check the differences between two xml strings but my code is not detecting any changes in xml strings!
for ex my first string contains :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>654654</Phone_1>
<Phone_2>654654564</Phone_2>
<Fax>2323232</Fax>
<Website>ewewew</Website>
<Mobile_No>23232323232</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 00:00:00</Start_Activity_Date>
<End_Activity_Date>2016-01-03 00:00:00</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
the second string is :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>11111</Phone_1>
<Phone_2>6546111154564</Phone_2>
<Fax>11111</Fax>
<Website>11111</Website>
<Mobile_No>11111</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 8:01:50</Start_Activity_Date>
<End_Activity_Date>2016-01-03 11:20:10</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
as you can see there are some differences in the values of the objects!
I've tried simplexmlload and then array_diff and jason encode and decode and comparing the jason but there was not chance to detect the differences.
any suggestion how to accomplish that ?
my array diff code :
$result = array_diff($Data1, $Data2);
if(empty($result)){
// the XML documents are the same
$res = "No changes";
} else {
// they are different
$res = "There are Some changes";
}
You can leave the data as raw text ane see the difference by using the following
<?php
$difference = xdiff_string_diff($Data1, $Data2);
Ok I solved the problem using simple if comparison method and it worked.
I first opened two xml files and then i copared them using method below, if i change a value/structure in second xml file it gives me "there are some changes".
$file = './Result.xml';
if (file_exists($file)) {
$Data = file_get_contents($file);
} else {
exit('Failed to open ' . $file);
}
$file2 = './Result2.xml';
if (file_exists($file2)) {
$Data2 = file_get_contents($file2);
} else {
exit('Failed to open ' . $file2);
}
if ($Data === $Data2) {
// the XML documents are the same
$res = "No changes";
} else {
// they are different: print the reason why
$res = "There are Some changes";
}

Adding xml node on top of file or reverse the loop

I am using xml. Reading the xml-document works fine, adding nodes works fine to but I want the node to add on top of the xml file. Is this possible or is this a nogo?
The reason I want this is because when I display the xml file I want the last added node, displayed as the newest one, on top.
I display the xml with this loop:
foreach($xml->xpath("//user[#id='12345678']") as $user){
foreach($user->children() as $action => $data){
echo"<li>";
echo $data->content;
echo $data->date;
echo"</li>";
}
}
If there is a way to reverse the loop or another way I'm fine with that to, it doesn't have to be adding the first node on top. Below are the file how I add the node and the structure of the xml-file.
Does anyone have an idea how to solve this?
addxml.php
<?php
$file = "actielijst.xml";
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$xml = new DOMDocument();
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");
// get document element
echo "<xmp>OLD:\n". $xml->saveXML() ."</xmp>";
$root = $xml->documentElement;
$content = $xml->createElement("content");
$contentText = $xml->createTextNode("Nieuwe Factuur Mei");
$content->appendChild($contentText);
$date = $xml->createElement("date");
$dateText = $xml->createTextNode("23-12-2010");
$date->appendChild($dateText);
$action = $xml->createElement("action");
$action->appendChild($date);
$action->appendChild($content);
$root->appendChild($action);
$xml->save("actielijst.xml") or die("Error");
?>
actielijst.xml
<?xml version="1.0"?>
<userid>
-------> Insert new action here <------
<action>
<date>23-01-2010</date>
<content>nieuwe factuur</content>
</action>
<action>
<date>23-01-2010</date>
<content>karten op 01-02</content>
</action>
</userid>
You can use xpath to capture every parent node (action in your case) and then reverse the array...
$users_arr = array_reverse($xml->xpath("action"));
Now you can loop through this array!
This will helps
<?php
$file = "actielijst.xml";
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$xml = simplexml_load_string($str);
$action = $xml->addChild('action');
$action->addChild('content','sundar');
$action->addChild('date','23-12-2010');
header('content-type: application/xml');
echo $xml->saveXML();

SQL data to XML file

Is it possible to save the below output to an XML file as its currently just displayed in the source?
$host = "localhost"; // host name
$user = "#"; // database user name
$pass = "#"; // database password
$database = "#"; // database name
// connecting to database
$connect = #mysql_connect($host,$user,$pass)or die (#mysql_error());
// selecting database
#mysql_select_db($database,$connect) or die (#mysql_error());
// default header(don't delete)
header("Content-Type: text/xml;charset=iso-8859-1");
echo '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// mytable = your content table name
$query = #mysql_query("SELECT * FROM urls");
while($row = #mysql_fetch_array($query)){
// [url] = content url
$url = $row['url'];
// [time] = content date
$date = date("Y-m-d", $row['time']);
// NO CHANGES BELOW
echo
'<url>
<loc>' . $url .'</loc>
<lastmod>'. $date .'</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
';
}
echo '</urlset>';
I know I can use .htaccess to make the file be seen as an XML format however I want the data to be saved onto an actual file.
You could try changing each echo to append the line to a string variable, for example:
// Instead of
echo '<?xml version="1.0"?>';
echo '<url>';
// etc.
$xml = '<?xml version="1.0"?>';
$xml .= '<url>';
// and so on
Then use one of the file functions to save to a file. file_put_contents is a simple method:
file_put_contents("/path/to/file.xml", $xml);
A more robust solution, if you want to take this further, could be to use the DOM module to build the XML structure:
$document = new DOMDocument("1.0");
$root = $document->createElement("urlset");
$root->setAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
$document->appendChild($root);
while ($row = mysql_query($query)) {
$item = $document->createElement("url");
$root->append($item);
// etc.
}
echo $document->saveXML();
NOTE: This answer assumes that by "save file" you mean "trigger the Save As dialog in the browser when someone views the page".
text/xml isn't really the correct content-type. You really should at least application/xml for generic XML or the appropriate content type for XML sub-formats such as RSS or docx.
If you want to trigger a file download dialog in the client browser, then you also need to send a content-disposition header that tells the browser that you want it to download the file and give a preferred filename.
There are some issues with your code that need addressing too.
Overuse of # for error suppression. This is a bad idea for a huge variety of reasons. Remove the # operators and handle any generated errors in a more robust way.
Your character encoding heading specifies one character set (latin-1) but your XML preamble specifies a totally different one (UTF-8). That's a recipe for disaster.
Use output buffers
ob_start();
... do everything you actually did before ...
$content = ob_get_contents();
ob_end_clean();
//Write to a file
file_put_contents('filename.xml', $content);
And thats all...
Using fwrite it should be straight forward :
$f = fopen('data.xml', 'w'); //open a file for writing
fwrite($f, $myxmltext); // write some things to it
fclose($f); // close it when finished

Problem with loading remote XML file

I'm trying to load a remote xml file using php.
This is my code:
$doc = new DOMDocument();
$doc->load($this->xml_file);
$file = $doc->getElementsByTagName('file');
$totalFiles = $file->length;
echo $totalFiles;
The remote xml file link is:
http://localhost/script/index.php?act=xml
This is the code in index.php:
$xml = '<?xml version="1.0"?><MultimediaGallery>';
$query = mysql_query('SELECT `id`,`image`,`desc` FROM `'
.confitem('database','prefix').'table` ORDER BY `id` DESC LIMIT '
.$start.','.$limit);
while($result = mysql_fetch_array($query))
{
$img = unserialize($result['image']);
$desc = unserialize($result['desc']);
$xml .= '<file type="photo"><thumb>'
.settings('site','url').'/'.OPATH_APPFOLDER.'/'
.OPATH_UPFOLDER.'/wallpapers/thumbs/'.$img[0].'</thumb><source>'
.settings('site','url')
.'/'.OPATH_APPFOLDER.'/'.OPATH_UPFOLDER
.'/wallpapers/'.$img[0].'</source><description>'
.$desc[$_SESSION['languagecode']].'</description></file>';
}
$xml .= '</MultimediaGallery>';
header("content-type: text/xml");
echo $xml;
When I visit this xml file link direct in the browser .. it's output to me xml file with this style :
<?xml version="1.0"?><MultimediaGallery><file type="photo"><thumb>http://localhost/script/application/data/wallpapers/thumbs/1116205566_42ce0841ab_s.jpg</thumb><source>http://localhost/script/application/data/wallpapers/1116205566_42ce0841ab_s.jpg</source><description>dfdfdfdf</description></file></MultimediaGallery>
When I execute the xml function which uses the dom to load the xml file I get this error:
Warning: DOMDocument::load()
[domdocument.load]: Extra content at
the end of the document in
http://localhost/script/index.php,
line: 2 in
C:\AppServ\www\script\application\libraries\wallpapers\multimedia.class.php
on line 46
Why is this happening?
Update:
I used dom to create the xml instead:
$xml = new DOMDocument('1.0');
$root = $xml->createElement('MultimediaGallery');
$xml->appendChild($root);
$query = mysql_query('SELECT `id`,`image`,`desc` FROM `'.confitem('database','prefix').'backgrounds` ORDER BY `id` DESC LIMIT '.$start.','.$limit);
while($result = mysql_fetch_array($query))
{
$img = unserialize($result['image']);
$desc = unserialize($result['desc']);
$element = $xml->createElement('file');
$root->appendChild($element);
$attr = $xml->createAttribute('type');
$element->appendChild($attr);
$attr_text = $xml->createTextNode('photo');
$attr->appendChild($attr_text);
$thumb = $xml->createElement('thumb');
$element->appendChild($thumb);
$thumb_text = $xml->createTextNode(settings('site','url').'/'.OPATH_APPFOLDER.'/'.OPATH_UPFOLDER.'/wallpapers/thumbs/'.$img[0]);
$thumb->appendChild($thumb_text);
$source = $xml->createElement('source');
$element->appendChild($source);
$source_text = $xml->createTextNode(settings('site','url').'/'.OPATH_APPFOLDER.'/'.OPATH_UPFOLDER.'/wallpapers/'.$img[0]);
$source->appendChild($source_text);
$description = $xml->createElement('description');
$element->appendChild($description);
$description_text = $xml->createTextNode($desc[$_SESSION['languagecode']]);
$description->appendChild($description_text);
}
header("content-type: text/xml");
echo $xml->saveXML();
But it still gives me the same error. I noticed some thing though, I tried to copy my output xml and save it in a file and read it using the dom parser and the result was that it's read successfully.
But when I try parsing the xml output by the php file then it throws an error.
Your XML is not well-formed. E.g there is something wrong with it.
Try to avoid making XML by concatenating strings because this will happen. You can use DomDocument you make XML as well as read it and manipulate it.
Make sure you have no leading or trailing white space in your XML generating script.
You should also be using CDATA

Categories