What is the best way to take a given PHP object and serialize it as XML? I am looking at simple_xml and I have used it to parse XML into objects, but it isn't clear to me how it works the other way around.
I'd agree with using PEAR's XML_Serializer, but if you want something simple that supports objects/arrays that have properties nested, you can use this.
class XMLSerializer {
// functions adopted from http://www.sean-barton.co.uk/2009/03/turning-an-array-or-object-into-xml-using-php/
public static function generateValidXmlFromObj(stdClass $obj, $node_block='nodes', $node_name='node') {
$arr = get_object_vars($obj);
return self::generateValidXmlFromArray($arr, $node_block, $node_name);
}
public static function generateValidXmlFromArray($array, $node_block='nodes', $node_name='node') {
$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
$xml .= '<' . $node_block . '>';
$xml .= self::generateXmlFromArray($array, $node_name);
$xml .= '</' . $node_block . '>';
return $xml;
}
private static function generateXmlFromArray($array, $node_name) {
$xml = '';
if (is_array($array) || is_object($array)) {
foreach ($array as $key=>$value) {
if (is_numeric($key)) {
$key = $node_name;
}
$xml .= '<' . $key . '>' . self::generateXmlFromArray($value, $node_name) . '</' . $key . '>';
}
} else {
$xml = htmlspecialchars($array, ENT_QUOTES);
}
return $xml;
}
}
take a look at PEAR's XML_Serializer package. I've used it with pretty good results. You can feed it arrays, objects etc and it will turn them into XML. It also has a bunch of options like picking the name of the root node etc.
Should do the trick
not quite an answer to the original question, but the way i solved my problem with this was by declaring my object as:
$root = '<?xml version="1.0" encoding="UTF-8"?><Activities/>';
$object = new simpleXMLElement($root);
as opposed to:
$object = new stdClass;
before i started adding any values!
Use a dom function to do it:
http://www.php.net/manual/en/function.dom-import-simplexml.php
Import the SimpleXML object and then save. The above link contains an example. :)
In a nutshell:
<?php
$array = array('hello' => 'world', 'good' => 'morning');
$xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><foo />");
foreach ($array as $k=>$v) {
$xml->addChild($k, $v);
}
?>
take a look at my version
class XMLSerializer {
/**
*
* The most advanced method of serialization.
*
* #param mixed $obj => can be an objectm, an array or string. may contain unlimited number of subobjects and subarrays
* #param string $wrapper => main wrapper for the xml
* #param array (key=>value) $replacements => an array with variable and object name replacements
* #param boolean $add_header => whether to add header to the xml string
* #param array (key=>value) $header_params => array with additional xml tag params
* #param string $node_name => tag name in case of numeric array key
*/
public static function generateValidXmlFromMixiedObj($obj, $wrapper = null, $replacements=array(), $add_header = true, $header_params=array(), $node_name = 'node')
{
$xml = '';
if($add_header)
$xml .= self::generateHeader($header_params);
if($wrapper!=null) $xml .= '<' . $wrapper . '>';
if(is_object($obj))
{
$node_block = strtolower(get_class($obj));
if(isset($replacements[$node_block])) $node_block = $replacements[$node_block];
$xml .= '<' . $node_block . '>';
$vars = get_object_vars($obj);
if(!empty($vars))
{
foreach($vars as $var_id => $var)
{
if(isset($replacements[$var_id])) $var_id = $replacements[$var_id];
$xml .= '<' . $var_id . '>';
$xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name);
$xml .= '</' . $var_id . '>';
}
}
$xml .= '</' . $node_block . '>';
}
else if(is_array($obj))
{
foreach($obj as $var_id => $var)
{
if(!is_object($var))
{
if (is_numeric($var_id))
$var_id = $node_name;
if(isset($replacements[$var_id])) $var_id = $replacements[$var_id];
$xml .= '<' . $var_id . '>';
}
$xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name);
if(!is_object($var))
$xml .= '</' . $var_id . '>';
}
}
else
{
$xml .= htmlspecialchars($obj, ENT_QUOTES);
}
if($wrapper!=null) $xml .= '</' . $wrapper . '>';
return $xml;
}
/**
*
* xml header generator
* #param array $params
*/
public static function generateHeader($params = array())
{
$basic_params = array('version' => '1.0', 'encoding' => 'UTF-8');
if(!empty($params))
$basic_params = array_merge($basic_params,$params);
$header = '<?xml';
foreach($basic_params as $k=>$v)
{
$header .= ' '.$k.'='.$v;
}
$header .= ' ?>';
return $header;
}
}
use WDDX:
http://uk.php.net/manual/en/wddx.examples.php
(if this extension is installed)
it's dedicated to that:
http://www.openwddx.org/
Here is my code used for serializing PHP objects to XML "understandable" by Microsoft .NET XmlSerializer.Deserialize
class XMLSerializer {
/**
* Get object class name without namespace
* #param object $object Object to get class name from
* #return string Class name without namespace
*/
private static function GetClassNameWithoutNamespace($object) {
$class_name = get_class($object);
return end(explode('\\', $class_name));
}
/**
* Converts object to XML compatible with .NET XmlSerializer.Deserialize
* #param type $object Object to serialize
* #param type $root_node Root node name (if null, objects class name is used)
* #return string XML string
*/
public static function Serialize($object, $root_node = null) {
$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
if (!$root_node) {
$root_node = self::GetClassNameWithoutNamespace($object);
}
$xml .= '<' . $root_node . ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
$xml .= self::SerializeNode($object);
$xml .= '</' . $root_node . '>';
return $xml;
}
/**
* Create XML node from object property
* #param mixed $node Object property
* #param string $parent_node_name Parent node name
* #param bool $is_array_item Is this node an item of an array?
* #return string XML node as string
* #throws Exception
*/
private static function SerializeNode($node, $parent_node_name = false, $is_array_item = false) {
$xml = '';
if (is_object($node)) {
$vars = get_object_vars($node);
} else if (is_array($node)) {
$vars = $node;
} else {
throw new Exception('Coś poszło nie tak');
}
foreach ($vars as $k => $v) {
if (is_object($v)) {
$node_name = ($parent_node_name ? $parent_node_name : self::GetClassNameWithoutNamespace($v));
if (!$is_array_item) {
$node_name = $k;
}
$xml .= '<' . $node_name . '>';
$xml .= self::SerializeNode($v);
$xml .= '</' . $node_name . '>';
} else if (is_array($v)) {
$xml .= '<' . $k . '>';
if (count($v) > 0) {
if (is_object(reset($v))) {
$xml .= self::SerializeNode($v, self::GetClassNameWithoutNamespace(reset($v)), true);
} else {
$xml .= self::SerializeNode($v, gettype(reset($v)), true);
}
} else {
$xml .= self::SerializeNode($v, false, true);
}
$xml .= '</' . $k . '>';
} else {
$node_name = ($parent_node_name ? $parent_node_name : $k);
if ($v === null) {
continue;
} else {
$xml .= '<' . $node_name . '>';
if (is_bool($v)) {
$xml .= $v ? 'true' : 'false';
} else {
$xml .= htmlspecialchars($v, ENT_QUOTES);
}
$xml .= '</' . $node_name . '>';
}
}
}
return $xml;
}
}
example:
class GetProductsCommandResult {
public $description;
public $Errors;
}
class Error {
public $id;
public $error;
}
$obj = new GetProductsCommandResult();
$obj->description = "Teścik";
$obj->Errors = array();
$obj->Errors[0] = new Error();
$obj->Errors[0]->id = 666;
$obj->Errors[0]->error = "Sth";
$obj->Errors[1] = new Error();
$obj->Errors[1]->id = 666;
$obj->Errors[1]->error = null;
$xml = XMLSerializer::Serialize($obj);
results in:
<?xml version="1.0" encoding="UTF-8"?>
<GetProductsCommandResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<description>Teścik</description>
<Errors>
<Error>
<id>666</id>
<error>Sth</error>
</Error>
<Error>
<id>666</id>
</Error>
</Errors>
</GetProductsCommandResult>
I know this is an old question, but recently I had to generate complex XML structures.
My approach contains advanced OOP principles. The idea is to serialize the parent object who contains multiple children and subchildren.
Nodes get names from the class names but you can override the class name with the first parameter when creating an object for serialization.
You can create: a Simple node, without child nodes, EntityList and ArrayList. EntityList is a list of objects of the same class, but an ArrayList may have different objects.
Each object has to extend the abstract class SerializeXmlAbstract in order to match first input parameter in class: Object2xml, method serialize($object, $name = NULL, $prefix = FALSE).
By default, if you don't provide the second parameter, the root XML node will have the class name of the given object. The third parameter indicates if root node name has a prefix or not. Prefix is hardcoded as a private property in Export2xml class.
interface SerializeXml {
public function hasAttributes();
public function getAttributes();
public function setAttributes($attribs = array());
public function getNameOwerriden();
public function isNameOwerriden();
}
abstract class SerializeXmlAbstract implements SerializeXml {
protected $attributes;
protected $nameOwerriden;
function __construct($name = NULL) {
$this->nameOwerriden = $name;
}
public function getAttributes() {
return $this->attributes;
}
public function getNameOwerriden() {
return $this->nameOwerriden;
}
public function setAttributes($attribs = array()) {
$this->attributes = $attribs;
}
public function hasAttributes() {
return (is_array($this->attributes) && count($this->attributes) > 0) ? TRUE : FALSE;
}
public function isNameOwerriden() {
return $this->nameOwerriden != NULL ? TRUE : FALSE;
}
}
abstract class Entity_list extends SplObjectStorage {
protected $_listItemType;
public function __construct($type) {
$this->setListItemType($type);
}
private function setListItemType($param) {
$this->_listItemType = $param;
}
public function detach($object) {
if ($object instanceOf $this->_listItemType) {
parent::detach($object);
}
}
public function attach($object, $data = null) {
if ($object instanceOf $this->_listItemType) {
parent::attach($object, $data);
}
}
}
abstract class Array_list extends SerializeXmlAbstract {
protected $_listItemType;
protected $_items;
public function __construct() {
//$this->setListItemType($type);
$this->_items = new SplObjectStorage();
}
protected function setListItemType($param) {
$this->_listItemType = $param;
}
public function getArray() {
$return = array();
$this->_items->rewind();
while ($this->_items->valid()) {
$return[] = $this->_items->current();
$this->_items->next();
}
// print_r($return);
return $return;
}
public function detach($object) {
if ($object instanceOf $this->_listItemType) {
if (in_array($this->_items->contains($object))) {
$this->_items->detach($object);
}
}
}
public function attachItem($ob) {
$this->_items->attach($ob);
}
}
class Object2xml {
public $rootPrefix = "ernm";
private $addPrefix;
public $xml;
public function serialize($object, $name = NULL, $prefix = FALSE) {
if ($object instanceof SerializeXml) {
$this->xml = new DOMDocument('1.0', 'utf-8');
$this->xml->appendChild($this->object2xml($object, $name, TRUE));
$this->xml->formatOutput = true;
echo $this->xml->saveXML();
} else {
die("Not implement SerializeXml interface");
}
}
protected function object2xml(SerializeXmlAbstract $object, $nodeName = NULL, $prefix = null) {
$single = property_exists(get_class($object), "value");
$nName = $nodeName != NULL ? $nodeName : get_class($object);
if ($prefix) {
$nName = $this->rootPrefix . ":" . $nName;
}
if ($single) {
$ref = $this->xml->createElement($nName);
} elseif (is_object($object)) {
if ($object->isNameOwerriden()) {
$nodeName = $object->getNameOwerriden();
}
$ref = $this->xml->createElement($nName);
if ($object->hasAttributes()) {
foreach ($object->getAttributes() as $key => $value) {
$ref->setAttribute($key, $value);
}
}
foreach (get_object_vars($object) as $n => $prop) {
switch (gettype($prop)) {
case "object":
if ($prop instanceof SplObjectStorage) {
$ref->appendChild($this->handleList($n, $prop));
} elseif ($prop instanceof Array_list) {
$node = $this->object2xml($prop);
foreach ($object->ResourceGroup->getArray() as $key => $value) {
$node->appendChild($this->object2xml($value));
}
$ref->appendChild($node);
} else {
$ref->appendChild($this->object2xml($prop));
}
break;
default :
if ($prop != null) {
$ref->appendChild($this->xml->createElement($n, $prop));
}
break;
}
}
} elseif (is_array($object)) {
foreach ($object as $value) {
$ref->appendChild($this->object2xml($value));
}
}
return $ref;
}
private function handleList($name, SplObjectStorage $param, $nodeName = NULL) {
$lst = $this->xml->createElement($nodeName == NULL ? $name : $nodeName);
$param->rewind();
while ($param->valid()) {
if ($param->current() != null) {
$lst->appendChild($this->object2xml($param->current()));
}
$param->next();
}
return $lst;
}
}
This is code you need to be able to get valid xml from objects. Next sample produces this xml:
<InsertMessage priority="high">
<NodeSimpleValue firstAttrib="first" secondAttrib="second">simple value</NodeSimpleValue>
<Arrarita>
<Title>PHP OOP is great</Title>
<SequenceNumber>1</SequenceNumber>
<Child>
<FirstChild>Jimmy</FirstChild>
</Child>
<Child2>
<FirstChild>bird</FirstChild>
</Child2>
</Arrarita>
<ThirdChild>
<NodeWithChilds>
<FirstChild>John</FirstChild>
<ThirdChild>James</ThirdChild>
</NodeWithChilds>
<NodeWithChilds>
<FirstChild>DomDocument</FirstChild>
<SecondChild>SplObjectStorage</SecondChild>
</NodeWithChilds>
</ThirdChild>
</InsertMessage>
Classes needed for this xml are:
class NodeWithArrayList extends Array_list {
public $Title;
public $SequenceNumber;
public function __construct($name = NULL) {
echo $name;
parent::__construct($name);
}
}
class EntityListNode extends Entity_list {
public function __construct($name = NULL) {
parent::__construct($name);
}
}
class NodeWithChilds extends SerializeXmlAbstract {
public $FirstChild;
public $SecondChild;
public $ThirdChild;
public function __construct($name = NULL) {
parent::__construct($name);
}
}
class NodeSimpleValue extends SerializeXmlAbstract {
protected $value;
public function getValue() {
return $this->value;
}
public function setValue($value) {
$this->value = $value;
}
public function __construct($name = NULL) {
parent::__construct($name);
}
}
And finally code that instantiate objects is:
$firstChild = new NodeSimpleValue("firstChild");
$firstChild->setValue( "simple value" );
$firstChild->setAttributes(array("firstAttrib" => "first", "secondAttrib" => "second"));
$secondChild = new NodeWithArrayList("Arrarita");
$secondChild->Title = "PHP OOP is great";
$secondChild->SequenceNumber = 1;
$firstListItem = new NodeWithChilds();
$firstListItem->FirstChild = "John";
$firstListItem->ThirdChild = "James";
$firstArrayItem = new NodeWithChilds("Child");
$firstArrayItem->FirstChild = "Jimmy";
$SecondArrayItem = new NodeWithChilds("Child2");
$SecondArrayItem->FirstChild = "bird";
$secondListItem = new NodeWithChilds();
$secondListItem->FirstChild = "DomDocument";
$secondListItem->SecondChild = "SplObjectStorage";
$secondChild->attachItem($firstArrayItem);
$secondChild->attachItem($SecondArrayItem);
$list = new EntityListNode("NodeWithChilds");
$list->attach($firstListItem);
$list->attach($secondListItem);
$message = New NodeWithChilds("InsertMessage");
$message->setAttributes(array("priority" => "high"));
$message->FirstChild = $firstChild;
$message->SecondChild = $secondChild;
$message->ThirdChild = $list;
$object2xml = new Object2xml();
$object2xml->serialize($message, "xml", TRUE);
Hope it will help someone.
Cheers,
Siniša
Use recursive method, like this:
private function ReadProperty($xmlElement, $object) {
foreach ($object as $key => $value) {
if ($value != null) {
if (is_object($value)) {
$element = $this->xml->createElement($key);
$this->ReadProperty($element, $value);
$xmlElement->AppendChild($element);
} elseif (is_array($value)) {
$this->ReadProperty($xmlElement, $value);
} else {
$this->AddAttribute($xmlElement, $key, $value);
}
}
}
}
Here the complete example:
http://www.tyrodeveloper.com/2018/09/convertir-clase-en-xml-con-php.html
I recently created a class available via git that resolves this problem:
https://github.com/zappz88/XMLSerializer
Here is the class structure, and keep in mind that you will need to define the root properly for format proper xml:
class XMLSerializer {
private $OpenTag = "<";
private $CloseTag = ">";
private $BackSlash = "/";
public $Root = "root";
public function __construct() {
}
private function Array_To_XML($array, $arrayElementName = "element_", $xmlString = "")
{
if($xmlString === "")
{
$xmlString = "{$this->OpenTag}{$this->Root}{$this->CloseTag}";
}
$startTag = "{$this->OpenTag}{$arrayElementName}{$this->CloseTag}";
$xmlString .= $startTag;
foreach($array as $key => $value){
if(gettype($value) === "string" || gettype($value) === "boolean" || gettype($value) === "integer" || gettype($value) === "double" || gettype($value) === "float")
{
$elementStartTag = "{$this->OpenTag}{$arrayElementName}_{$key}{$this->CloseTag}";
$elementEndTag = "{$this->OpenTag}{$this->BackSlash}{$arrayElementName}_{$key}{$this->CloseTag}";
$xmlString .= "{$elementStartTag}{$value}{$elementEndTag}";
continue;
}
else if(gettype($value) === "array")
{
$xmlString = $this->Array_To_XML($value, $arrayElementName, $xmlString);
continue;
}
else if(gettype($value) === "object")
{
$xmlString = $this->Object_To_XML($value, $xmlString);
continue;
}
else
{
continue;
}
}
$endTag = "{$this->OpenTag}{$this->BackSlash}{$arrayElementName}{$this->CloseTag}";
$xmlString .= $endTag;
return $xmlString;
}
private function Object_To_XML($objElement, $xmlString = "")
{
if($xmlString === "")
{
$xmlString = "{$this->OpenTag}{$this->Root}{$this->CloseTag}";
}
foreach($objElement as $key => $value){
if(gettype($value) !== "array" && gettype($value) !== "object")
{
$startTag = "{$this->OpenTag}{$key}{$this->CloseTag}";
$endTag = "{$this->OpenTag}{$this->BackSlash}{$key}{$this->CloseTag}";
$xmlString .= "{$startTag}{$value}{$endTag}";
continue;
}
else if(gettype($value) === "array")
{
$xmlString = $this->Array_To_XML($value, $key, $xmlString);
continue;
}
else if(gettype($value) === "object")
{
$xmlString = $this->Object_To_XML($value, $xmlString);
continue;
}
else
{
continue;
}
}
return $xmlString;
}
public function Serialize_Object($element, $xmlString = "")
{
$endTag = "{$this->OpenTag}{$this->BackSlash}{$this->Root}{$this->CloseTag}";
return "{$this->Object_To_XML($element, $xmlString)}{$endTag}";
}
public function Serialize_Array($element, $xmlString = "")
{
$endTag = "{$this->OpenTag}{$this->BackSlash}{$this->Root}{$this->CloseTag}";
return "{$this->Array_To_XML($element, $xmlString)}{$endTag}";
}
}
While I agree with #philfreo and his reasoning that you shouldn't be dependant on PEAR, his solution is still not quite there. There are potential issues when the key could be a string that contains any of the following characters:
<
>
\s (space)
"
'
Any of these will throw off the format, as XML uses these characters in its grammar. So, without further ado, here is a simple solution to that very possible occurrence:
function xml_encode( $var, $indent = false, $i = 0 ) {
$version = "1.0";
if ( !$i ) {
$data = '<?xml version="1.0"?>' . ( $indent ? "\r\n" : '' )
. '<root vartype="' . gettype( $var ) . '" xml_encode_version="'. $version . '">' . ( $indent ? "\r\n" : '' );
}
else {
$data = '';
}
foreach ( $var as $k => $v ) {
$data .= ( $indent ? str_repeat( "\t", $i ) : '' ) . '<var vartype="' .gettype( $v ) . '" varname="' . htmlentities( $k ) . '"';
if($v == "") {
$data .= ' />';
}
else {
$data .= '>';
if ( is_array( $v ) ) {
$data .= ( $indent ? "\r\n" : '' ) . xml_encode( $v, $indent, $verbose, ($i + 1) ) . ( $indent ? str_repeat("\t", $i) : '' );
}
else if( is_object( $v ) ) {
$data .= ( $indent ? "\r\n" : '' ) . xml_encode( json_decode( json_encode( $v ), true ), $indent, $verbose, ($i + 1)) . ($indent ? str_repeat("\t", $i) : '');
}
else {
$data .= htmlentities( $v );
}
$data .= '</var>';
}
$data .= ($indent ? "\r\n" : '');
}
if ( !$i ) {
$data .= '</root>';
}
return $data;
}
Here is a sample usage:
// sample object
$tests = Array(
"stringitem" => "stringvalue",
"integeritem" => 1,
"floatitem" => 1.00,
"arrayitems" => Array("arrayvalue1", "arrayvalue2"),
"hashitems" => Array( "hashkey1" => "hashkey1value", "hashkey2" => "hashkey2value" ),
"literalnull" => null,
"literalbool" => json_decode( json_encode( 1 ) )
);
// add an objectified version of itself as a child
$tests['objectitem'] = json_decode( json_encode( $tests ), false);
// convert and output
echo xml_encode( $tests );
/*
// output:
<?xml version="1.0"?>
<root vartype="array" xml_encode_version="1.0">
<var vartype="integer" varname="integeritem">1</var>
<var vartype="string" varname="stringitem">stringvalue</var>
<var vartype="double" varname="floatitem">1</var>
<var vartype="array" varname="arrayitems">
<var vartype="string" varname="0">arrayvalue1</var>
<var vartype="string" varname="1">arrayvalue2</var>
</var>
<var vartype="array" varname="hashitems">
<var vartype="string" varname="hashkey1">hashkey1value</var>
<var vartype="string" varname="hashkey2">hashkey2value</var>
</var>
<var vartype="NULL" varname="literalnull" />
<var vartype="integer" varname="literalbool">1</var>
<var vartype="object" varname="objectitem">
<var vartype="string" varname="stringitem">stringvalue</var>
<var vartype="integer" varname="integeritem">1</var>
<var vartype="integer" varname="floatitem">1</var>
<var vartype="array" varname="arrayitems">
<var vartype="string" varname="0">arrayvalue1</var>
<var vartype="string" varname="1">arrayvalue2</var>
</var>
<var vartype="array" varname="hashitems">
<var vartype="string" varname="hashkey1">hashkey1value</var>
<var vartype="string" varname="hashkey2">hashkey2value</var>
</var>
<var vartype="NULL" varname="literalnull" />
<var vartype="integer" varname="literalbool">1</var>
</var>
</root>
*/
Notice that the key names are stored in the varname attribute (html encoded), and even the type is stored, so symmetric de-serialization is possible. There is only one issue with this: it will not serialize classes, only the instantiated object, which will not include the class methods. This is only functional for passing "data" back and forth.
I hope this helps someone, even though this was answered long ago.
Well, while a little dirty, you could always run a loop on the object's properties...
$_xml = '';
foreach($obj as $key => $val){
$_xml .= '<' . $key . '>' . $val . '</' . $key . ">\n";
}
Using fopen/fwrite/fclose you could generate an XML doc with the $_xml variable as content. It's ugly, but it would work.
Related
I would like assign a user to a group with API REST.
But it doesn't work.
I use POST /groups/:id/users.:format syntax (see Rest Groups)
User with this id exists in redmine and group too.
In redmine log I can see:
Processing by GroupsController#add_users as XML
Parameters: {"group"=>{"user_id"=>"34"}, "key"=>"81aa228c55ac5cfe4264a566ef67ac27702da8eb", "id"=>"5"}
Current user: admin (id=1)
Rendering common/error_messages.api.rsb
Rendered common/error_messages.api.rsb (0.1ms)
Completed 422 Unprocessable Entity in 4ms (Views: 0.4ms | ActiveRecord: 1.3ms)
And in API's response:
Code Error :422
Message : User is invalid
In request body : id of user
I use ActiveResouce for REST API.
$method = 'users'
$options = array('user_id' => user's id to add)
/**
* Posts to a specified custom method on the current object via:
*
* POST /collection/id/method.xml
*/
function post ($method, $options = array (), $start_tag = false) {
$req = $this->site . $this->element_name_plural;
if ($this->_data['id']) {
$req .= '/' . $this->_data['id'];
}
$req .= '/' . $method . '.xml';
return $this->_send_and_receive ($req, 'POST', $options, $start_tag);
}
And this function for send request and parse the response :
/**
* Build the request, call _fetch() and parse the results.
*/
function _send_and_receive ($url, $method, $data = array (), $start_tag = false) {
$params = '';
$el = $start_tag ? $start_tag : $this->element_name; // Singular this time
if ($this->request_format == 'url') {
foreach ($data as $k => $v) {
if ($k != 'id' && $k != 'created-at' && $k != 'updated-at') {
$params .= '&' . $el . '[' . str_replace ('-', '_', $k) . ']=' . rawurlencode ($v);
}
}
$params = substr ($params, 1);
} elseif ($this->request_format == 'xml') {
$params = '<?xml version="1.0" encoding="UTF-8"?><' . $el . ">\n";
foreach ($data as $k => $v) {
if ($k != 'id' && $k != 'created-at' && $k != 'updated-at') {
$params .= $this->_build_xml ($k, $v);
}
}
$params .= '</' . $el . '>';
}
if ($this->extra_params !== false) {
if(strpos($url, '?'))
{
$url = $url .'&'.$this->extra_params;
}
else
{
$url = $url .'?'.$this->extra_params;
}
}
$this->request_body = $params;
$this->request_uri = $url;
$this->request_method = $method;
$res = $this->_fetch ($url, $method, $params);
if ($res === false) {
return $this;
}
// Keep splitting off any top headers until we get to the (XML) body:
while (strpos($res, "HTTP/") === 0) {
list ($headers, $res) = explode ("\r\n\r\n", $res, 2);
$this->response_headers = $headers;
$this->response_body = $res;
if (preg_match ('/HTTP\/[0-9]\.[0-9] ([0-9]+)/', $headers, $regs)) {
$this->response_code = $regs[1];
} else {
$this->response_code = false;
}
if (! $res) {
return $this;
} elseif ($res == ' ') {
$this->error = 'Empty reply';
return $this;
}
}
// parse XML response
$xml = new SimpleXMLElement ($res);
// normalize xml element name in case rails ressource contains an underscore
if (str_replace ('-', '_', $xml->getName ()) == $this->element_name_plural) {
// multiple
$res = array ();
$cls = get_class ($this);
foreach ($xml->children () as $child) {
$obj = new $cls;
foreach ((array) $child as $k => $v) {
$k = str_replace ('-', '_', $k);
if (isset ($v['nil']) && $v['nil'] == 'true') {
continue;
} else {
$obj->_data[$k] = $v;
}
}
$res[] = $obj;
}
return $res;
} elseif ($xml->getName () == 'errors') {
// parse error message
$this->error = $xml->error;
$this->errno = $this->response_code;
return false;
}
foreach ((array) $xml as $k => $v) {
$k = str_replace ('-', '_', $k);
if (isset ($v['nil']) && $v['nil'] == 'true') {
continue;
} else {
$this->_data[$k] = $v;
}
}
return $this;
}
Thank you
I've tried to import an xlsx file to array, but noticed, that it contains simple text whereas if I open it in OpenOffice, I can see some words in the cell are bold.
#items: array:2 [
"url" => "theurl"
"meta_title" => "text with one bold word"
]
Is there a way to get somehow text with <b>one</b> bold word?
PHPExcel wiki says nothing about it. Its valueBinder applies only to csv and html files.
Thanks to Mark Baker. The HTML Writer code helps to create simple converter. Usage:
$richtextService = new RichTextService();
$value = $reader->getActiveSheet()->getCell('F2')->getValue();
$html = $richtextService->getHTML($value); // html in it
And the class:
namespace App\Services;
use PHPExcel_RichText;
use PHPExcel_RichText_Run;
use PHPExcel_Style_Font;
class RichTextService{
/**
* Takes array where of CSS properties / values and converts to CSS stri$
*
* #param array
* #return string
*/
private function assembleCSS($pValue = array())
{
$pairs = array();
foreach ($pValue as $property => $value) {
$pairs[] = $property . ':' . $value;
}
$string = implode('; ', $pairs);
return $string;
}
/**
* Create CSS style (PHPExcel_Style_Font)
*
* #param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font
* #return array
*/
private function createCSSStyleFont(PHPExcel_Style_Font $pStyle)
{
// Construct CSS
$css = array();
// Create CSS
if ($pStyle->getBold()) {
$css['font-weight'] = 'bold';
}
if ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE && $pStyle->getStrikethrough()) {
$css['text-decoration'] = 'underline line-through';
} elseif ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE) {
$css['text-decoration'] = 'underline';
} elseif ($pStyle->getStrikethrough()) {
$css['text-decoration'] = 'line-through';
}
if ($pStyle->getItalic()) {
$css['font-style'] = 'italic';
}
$css['color'] = '#' . $pStyle->getColor()->getRGB();
$css['font-family'] = '\'' . $pStyle->getName() . '\'';
$css['font-size'] = $pStyle->getSize() . 'pt';
return $css;
}
/**
*
* #param PHPExcel_RichText|string $value
* #return string
*/
public function getHTML($value) {
if(is_string($value)) {
return $value;
}
$cellData = '';
if ($value instanceof PHPExcel_RichText) {
// Loop through rich text elements
$elements = $value->getRichTextElements();
foreach ($elements as $element) {
// Rich text start?
if ($element instanceof PHPExcel_RichText_Run) {
$cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($element->getFont())) . '">';
if ($element->getFont()->getSuperScript()) {
$cellData .= '<sup>';
} elseif ($element->getFont()->getSubScript()) {
$cellData .= '<sub>';
}
}
// Convert UTF8 data to PCDATA
$cellText = $element->getText();
$cellData .= htmlspecialchars($cellText);
if ($element instanceof PHPExcel_RichText_Run) {
if ($element->getFont()->getSuperScript()) {
$cellData .= '</sup>';
} elseif ($element->getFont()->getSubScript()) {
$cellData .= '</sub>';
}
$cellData .= '</span>';
}
}
}
return str_replace("\n", "<br>\n", $cellData);
}
}
With this small adaptions this solution works with the successor PhpSpreadsheet:
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\RichText;
use PhpOffice\PhpSpreadsheet\RichText\Run;
use PhpOffice\PhpSpreadsheet\Style\Font;
class RichTextService {
/**
* Takes array where of CSS properties / values and converts to CSS stri$
*
* #param array
* #return string
*/
private function assembleCSS($pValue = array())
{
$pairs = array();
foreach ($pValue as $property => $value) {
$pairs[] = $property . ':' . $value;
}
$string = implode('; ', $pairs);
return $string;
}
/**
* Create CSS style (Font)
*
* #param Font $pStyle Font
* #return array
*/
private function createCSSStyleFont(Font $pStyle)
{
// Construct CSS
$css = array();
// Create CSS
if ($pStyle->getBold()) {
$css['font-weight'] = 'bold';
}
if ($pStyle->getUnderline() != Font::UNDERLINE_NONE && $pStyle->getStrikethrough()) {
$css['text-decoration'] = 'underline line-through';
} elseif ($pStyle->getUnderline() != Font::UNDERLINE_NONE) {
$css['text-decoration'] = 'underline';
} elseif ($pStyle->getStrikethrough()) {
$css['text-decoration'] = 'line-through';
}
if ($pStyle->getItalic()) {
$css['font-style'] = 'italic';
}
$css['color'] = '#' . $pStyle->getColor()->getRGB();
$css['font-family'] = '\'' . $pStyle->getName() . '\'';
$css['font-size'] = $pStyle->getSize() . 'pt';
return $css;
}
/**
*
* #param RichText|string $value
* #return string
*/
public function getHTML($value) {
if(is_string($value)) {
return $value;
}
$cellData = '';
if ($value instanceof PhpOffice\PhpSpreadsheet\RichText\RichText) {
// Loop through rich text elements
$elements = $value->getRichTextElements();
foreach ($elements as $element) {
// Rich text start?
print_r($element);
if ($element instanceof PhpOffice\PhpSpreadsheet\RichText\Run) {
$cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($element->getFont())) . '">';
if ($element->getFont()->getSuperScript()) {
$cellData .= '<sup>';
} elseif ($element->getFont()->getSubScript()) {
$cellData .= '<sub>';
}
}
// Convert UTF8 data to PCDATA
$cellText = $element->getText();
$cellData .= htmlspecialchars($cellText);
if ($element instanceof PhpOffice\PhpSpreadsheet\RichText\Run) {
if ($element->getFont()->getSuperScript()) {
$cellData .= '</sup>';
} elseif ($element->getFont()->getSubScript()) {
$cellData .= '</sub>';
}
$cellData .= '</span>';
}
}
}
return str_replace("\n", "<br>\n", $cellData);
}
}
I am having trouble find the problem in figuring out the problem using merchant-sdk-php I found on github. For some reason its throwing this error. I tried looking at the code but I dont under stand it or see the problem.
Fatal error: Call to undefined method stdClass::toXMLString() in /home/content/08/10639508/html/wp-content/plugins/donation-manager/library/vendor/paypal/paypal-sdk-core-php-bc7822a/lib/PPXmlMessage.php on line 89
<?php
/**
* #author
*/
abstract class PPXmlMessage
{
/**
* #return string
*/
public function toSOAP()
{
return $this->toXMLString();
}
/**
* #return string
*/
public function toXMLString()
{
if (count($properties = get_object_vars($this)) >= 2 && array_key_exists('value', $properties)) {
$attributes = array();
foreach (array_keys($properties) as $property) {
if ($property === 'value') continue;
if (($annots = PPUtils::propertyAnnotations($this, $property)) && isset($annots['attribute'])) {
if (($propertyValue = $this->{$property}) === NULL || $propertyValue == NULL) {
$attributes[] = NULL;
continue;
}
$attributes[] = $property . '="' . PPUtils::escapeInvalidXmlCharsRegex($propertyValue) . '"';
}
}
if (count($attributes)) {
return implode(' ', $attributes) . '>' . PPUtils::escapeInvalidXmlCharsRegex($this->value);
}
}
$xml = array();
foreach ($properties as $property => $defaultValue) {
if (($propertyValue = $this->{$property}) === NULL || $propertyValue == NULL) {
continue;
}
if (is_array($defaultValue) || is_array($propertyValue)) {
foreach ($propertyValue as $item) {
if (!is_object($item)) {
$xml[] = $this->buildProperty($property, $item);
}else{
$xml[] = $this->buildProperty($property, $item);
}
}
} else {
$xml[] = $this->buildProperty($property, $propertyValue);
}
}
return implode($xml);
}
/**
* #param string $property
* #param PPXmlMessage|string $value
* #param string $namespace
* #return string
*/
private function buildProperty($property, $value, $namespace = 'ebl')
{
$annotations = PPUtils::propertyAnnotations($this, $property);
if (!empty($annotations['namespace'])) {
$namespace = $annotations['namespace'];
}
if (!empty($annotations['name'])) {
$property = $annotations['name'];
}
$el = '<' . $namespace . ':' . $property;
if (!is_object($value)) {
$el .= '>' . PPUtils::escapeInvalidXmlCharsRegex($value);
} else {
if (substr($value = $value->toXMLString(), 0, 1) === '<' || $value=='') {
$el .= '>' . $value;
} else {
$el .= ' ' . $value;
}
}
return $el . '</' . $namespace . ':' . $property . '>';
}
/**
* #param array $map
* #param string $prefix
*/
public function init(array $map = array(), $prefix = '')
{
if (empty($map)) {
return;
}
if (($first = reset($map)) && !is_array($first) && !is_numeric(key($map))) {
parent::init($map, $prefix);
return;
}
$propertiesMap = PPUtils::objectProperties($this);
$arrayCtr = array();
foreach ($map as $element) {
if (empty($element) || empty($element['name'])) {
continue;
} elseif (!array_key_exists($property = strtolower($element['name']), $propertiesMap)) {
if (!preg_match('~^(.+)[\[\(](\d+)[\]\)]$~', $property, $m)) {
continue;
}
$element['name'] = $m[1];
$element['num'] = $m[2];
}
$element['name'] = $propertiesMap[strtolower($element['name'])];
if(PPUtils::isPropertyArray($this, $element['name'])) {
$arrayCtr[$element['name']] = isset($arrayCtr[$element['name']]) ? ($arrayCtr[$element['name']]+1) : 0;
$element['num'] = $arrayCtr[$element['name']];
}
if (!empty($element["attributes"]) && is_array($element["attributes"])) {
foreach ($element["attributes"] as $key => $val) {
$element["children"][] = array(
'name' => $key,
'text' => $val,
);
}
if (isset($element['text'])) {
$element["children"][] = array(
'name' => 'value',
'text' => $element['text'],
);
}
$this->fillRelation($element['name'], $element);
} elseif (!empty($element['text'])) {
$this->{$element['name']} = $element['text'];
} elseif (!empty($element["children"]) && is_array($element["children"])) {
$this->fillRelation($element['name'], $element);
}
}
}
/**
* #param string $property
* #param array $element
*/
private function fillRelation($property, array $element)
{
if (!class_exists($type = PPUtils::propertyType($this, $property))) {
trigger_error("Class $type not found.", E_USER_NOTICE);
return; // just ignore
}
if (isset($element['num'])) { // array of objects
$this->{$property}[$element['num']] = $item = new $type();
$item->init($element['children']);
} else {
$this->{$property} = new $type();
$this->{$property}->init($element["children"]);
}
}
}
I had this exact same error (with my live application - it worked fine in my test code). I eventually realized that, when I copied over my test code into the live environment and changed my credentials and URLs from the sandbox ones to the live ones ... I somehow deleted a line of code initializing a PaymentDetailsType object before calling SetExpressCheckout. So this error seemed pretty unrelated, but it was just a problem with setting up the objects before making the call to PayPal.
Perchance are you using json_encode/decode on your PaymentDetail record? It seems that PayPal is very particular about the component classes; stdClass (which json_decode generates) won't cut it. Serialize works, but there are warnings about using it.
I use a script from here to generate my sitemaps.
I can call it with the browser with http://www.example.com/sitemap.php?update=pages and its working fine.
I need to call it as shell script so that I can automate it with the windows task scheduler. But the script needs to be changed to get the variables ?update=pages. But I don't manage to change it correctly.
Could anybody help me so that I can execute the script from command line with
...\php C:\path\to\script\sitemap.php update=pages. It would also be fine for me to hardcode the variables into the script since I wont change them anyway.
define("BASE_URL", "http://www.example.com/");
define ('BASE_URI', $_SERVER['DOCUMENT_ROOT'] . '/');
class Sitemap {
private $compress;
private $page = 'index';
private $index = 1;
private $count = 1;
private $urls = array();
public function __construct ($compress=true) {
ini_set('memory_limit', '75M'); // 50M required per tests
$this->compress = ($compress) ? '.gz' : '';
}
public function page ($name) {
$this->save();
$this->page = $name;
$this->index = 1;
}
public function url ($url, $lastmod='', $changefreq='', $priority='') {
$url = htmlspecialchars(BASE_URL . 'xx' . $url);
$lastmod = (!empty($lastmod)) ? date('Y-m-d', strtotime($lastmod)) : false;
$changefreq = (!empty($changefreq) && in_array(strtolower($changefreq), array('always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'))) ? strtolower($changefreq) : false;
$priority = (!empty($priority) && is_numeric($priority) && abs($priority) <= 1) ? round(abs($priority), 1) : false;
if (!$lastmod && !$changefreq && !$priority) {
$this->urls[] = $url;
} else {
$url = array('loc'=>$url);
if ($lastmod !== false) $url['lastmod'] = $lastmod;
if ($changefreq !== false) $url['changefreq'] = $changefreq;
if ($priority !== false) $url['priority'] = ($priority < 1) ? $priority : '1.0';
$this->urls[] = $url;
}
if ($this->count == 50000) {
$this->save();
} else {
$this->count++;
}
}
public function close() {
$this->save();
}
private function save () {
if (empty($this->urls)) return;
$file = "sitemaps/xx-sitemap-{$this->page}-{$this->index}.xml{$this->compress}";
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($this->urls as $url) {
$xml .= ' <url>' . "\n";
if (is_array($url)) {
foreach ($url as $key => $value) $xml .= " <{$key}>{$value}</{$key}>\n";
} else {
$xml .= " <loc>{$url}</loc>\n";
}
$xml .= ' </url>' . "\n";
}
$xml .= '</urlset>' . "\n";
$this->urls = array();
if (!empty($this->compress)) $xml = gzencode($xml, 9);
$fp = fopen(BASE_URI . $file, 'wb');
fwrite($fp, $xml);
fclose($fp);
$this->index++;
$this->count = 1;
$num = $this->index; // should have already been incremented
while (file_exists(BASE_URI . "xxb-sitemap-{$this->page}-{$num}.xml{$this->compress}")) {
unlink(BASE_URI . "xxc-sitemap-{$this->page}-{$num}.xml{$this->compress}");
$num++;
}
$this->index($file);
}
private function index ($file) {
$sitemaps = array();
$index = "sitemaps/xx-sitemap-index.xml{$this->compress}";
if (file_exists(BASE_URI . $index)) {
$xml = (!empty($this->compress)) ? gzfile(BASE_URI . $index) : file(BASE_URI . $index);
$tags = $this->xml_tag(implode('', $xml), array('sitemap'));
foreach ($tags as $xml) {
$loc = str_replace(BASE_URL, '', $this->xml_tag($xml, 'loc'));
$lastmod = $this->xml_tag($xml, 'lastmod');
$lastmod = ($lastmod) ? date('Y-m-d', strtotime($lastmod)) : date('Y-m-d');
if (file_exists(BASE_URI . $loc)) $sitemaps[$loc] = $lastmod;
}
}
$sitemaps[$file] = date('Y-m-d');
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($sitemaps as $loc => $lastmod) {
$xml .= ' <sitemap>' . "\n";
$xml .= ' <loc>' . BASE_URL . $loc . '</loc>' . "\n";
$xml .= ' <lastmod>' . $lastmod . '</lastmod>' . "\n";
$xml .= ' </sitemap>' . "\n";
}
$xml .= '</sitemapindex>' . "\n";
if (!empty($this->compress)) $xml = gzencode($xml, 9);
$fp = fopen(BASE_URI . $index, 'wb');
fwrite($fp, $xml);
fclose($fp);
}
private function xml_tag ($xml, $tag, &$end='') {
if (is_array($tag)) {
$tags = array();
while ($value = $this->xml_tag($xml, $tag[0], $end)) {
$tags[] = $value;
$xml = substr($xml, $end);
}
return $tags;
}
$pos = strpos($xml, "<{$tag}>");
if ($pos === false) return false;
$start = strpos($xml, '>', $pos) + 1;
$length = strpos($xml, "</{$tag}>", $start) - $start;
$end = strpos($xml, '>', $start + $length) + 1;
return ($end !== false) ? substr($xml, $start, $length) : false;
}
public function __destruct () {
$this->save();
}
}
// start part 2
$sitemap = new Sitemap;
if (get('pages')) {
$sitemap->page('pages');
$result = mysql_query("SELECT uri FROM app_uri");
while (list($url, $created) = mysql_fetch_row($result)) {
$sitemap->url($url, $created, 'monthly');
}
}
$sitemap->close();
unset ($sitemap);
function get ($name) {
return (isset($_GET['update']) && strpos($_GET['update'], $name) !== false) ? true : false;
}
?>
I could install wget (it's available for windows as well) and then call the url via localhost in the task scheduler script:
wget.exe "http://localhost/path/to/script.php?pages=test"
This way you wouldn't have to rewrite the php script.
Otherwise, if the script is meant for shell usage only, then pass variables via command line:
php yourscript.php variable1 variable2 ...
In the php script you can than access those variables using the $argv variable:
$variable1 = $argv[1];
$variable2 = $argv[2];
have a look on:
How to pass GET variables to php file with Shell?
which already answered the same question :).
I want to create a sitemap for a page with more than 30.000.000 pages. The page is daily updating, removing and adding new pages.
I found this php script which I would like to run with a cron job.
Sitemap php script
I have all URIs in the table "myuri" in the column "uri" entries are written e.g. "/this-is-a-page.html". What parameters do I need to add to the script to get it running on my table?
<?php
/*
* author: Kyle Gadd
* documentation: http://www.php-ease.com/classes/sitemap.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Sitemap {
private $compress;
private $page = 'index';
private $index = 1;
private $count = 1;
private $urls = array();
public function __construct ($compress=true) {
ini_set('memory_limit', '75M'); // 50M required per tests
$this->compress = ($compress) ? '.gz' : '';
}
public function page ($name) {
$this->save();
$this->page = $name;
$this->index = 1;
}
public function url ($url, $lastmod='', $changefreq='', $priority='') {
$url = htmlspecialchars(BASE_URL . $url);
$lastmod = (!empty($lastmod)) ? date('Y-m-d', strtotime($lastmod)) : false;
$changefreq = (!empty($changefreq) && in_array(strtolower($changefreq), array('always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'))) ? strtolower($changefreq) : false;
$priority = (!empty($priority) && is_numeric($priority) && abs($priority) <= 1) ? round(abs($priority), 1) : false;
if (!$lastmod && !$changefreq && !$priority) {
$this->urls[] = $url;
} else {
$url = array('loc'=>$url);
if ($lastmod !== false) $url['lastmod'] = $lastmod;
if ($changefreq !== false) $url['changefreq'] = $changefreq;
if ($priority !== false) $url['priority'] = ($priority < 1) ? $priority : '1.0';
$this->urls[] = $url;
}
if ($this->count == 50000) {
$this->save();
} else {
$this->count++;
}
}
public function close() {
$this->save();
$this->ping_search_engines();
}
private function save () {
if (empty($this->urls)) return;
$file = "sitemap-{$this->page}-{$this->index}.xml{$this->compress}";
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($this->urls as $url) {
$xml .= ' <url>' . "\n";
if (is_array($url)) {
foreach ($url as $key => $value) $xml .= " <{$key}>{$value}</{$key}>\n";
} else {
$xml .= " <loc>{$url}</loc>\n";
}
$xml .= ' </url>' . "\n";
}
$xml .= '</urlset>' . "\n";
$this->urls = array();
if (!empty($this->compress)) $xml = gzencode($xml, 9);
$fp = fopen(BASE_URI . $file, 'wb');
fwrite($fp, $xml);
fclose($fp);
$this->index++;
$this->count = 1;
$num = $this->index; // should have already been incremented
while (file_exists(BASE_URI . "sitemap-{$this->page}-{$num}.xml{$this->compress}")) {
unlink(BASE_URI . "sitemap-{$this->page}-{$num}.xml{$this->compress}");
$num++;
}
$this->index($file);
}
private function index ($file) {
$sitemaps = array();
$index = "sitemap-index.xml{$this->compress}";
if (file_exists(BASE_URI . $index)) {
$xml = (!empty($this->compress)) ? gzfile(BASE_URI . $index) : file(BASE_URI . $index);
$tags = $this->xml_tag(implode('', $xml), array('sitemap'));
foreach ($tags as $xml) {
$loc = str_replace(BASE_URL, '', $this->xml_tag($xml, 'loc'));
$lastmod = $this->xml_tag($xml, 'lastmod');
$lastmod = ($lastmod) ? date('Y-m-d', strtotime($lastmod)) : date('Y-m-d');
if (file_exists(BASE_URI . $loc)) $sitemaps[$loc] = $lastmod;
}
}
$sitemaps[$file] = date('Y-m-d');
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($sitemaps as $loc => $lastmod) {
$xml .= ' <sitemap>' . "\n";
$xml .= ' <loc>' . BASE_URL . $loc . '</loc>' . "\n";
$xml .= ' <lastmod>' . $lastmod . '</lastmod>' . "\n";
$xml .= ' </sitemap>' . "\n";
}
$xml .= '</sitemapindex>' . "\n";
if (!empty($this->compress)) $xml = gzencode($xml, 9);
$fp = fopen(BASE_URI . $index, 'wb');
fwrite($fp, $xml);
fclose($fp);
}
private function xml_tag ($xml, $tag, &$end='') {
if (is_array($tag)) {
$tags = array();
while ($value = $this->xml_tag($xml, $tag[0], $end)) {
$tags[] = $value;
$xml = substr($xml, $end);
}
return $tags;
}
$pos = strpos($xml, "<{$tag}>");
if ($pos === false) return false;
$start = strpos($xml, '>', $pos) + 1;
$length = strpos($xml, "</{$tag}>", $start) - $start;
$end = strpos($xml, '>', $start + $length) + 1;
return ($end !== false) ? substr($xml, $start, $length) : false;
}
public function ping_search_engines () {
$sitemap = BASE_URL . 'sitemap-index.xml' . $this->compress;
$engines = array();
$engines['www.google.com'] = '/webmasters/tools/ping?sitemap=' . urlencode($sitemap);
$engines['www.bing.com'] = '/webmaster/ping.aspx?siteMap=' . urlencode($sitemap);
$engines['submissions.ask.com'] = '/ping?sitemap=' . urlencode($sitemap);
foreach ($engines as $host => $path) {
if ($fp = fsockopen($host, 80)) {
$send = "HEAD $path HTTP/1.1\r\n";
$send .= "HOST: $host\r\n";
$send .= "CONNECTION: Close\r\n\r\n";
fwrite($fp, $send);
$http_response = fgets($fp, 128);
fclose($fp);
list($response, $code) = explode (' ', $http_response);
if ($code != 200) trigger_error ("{$host} ping was unsuccessful.<br />Code: {$code}<br />Response: {$response}");
}
}
}
public function __destruct () {
$this->save();
}
}
?>
There is already an example of usage on the page:
<?php
require_once ('php/classes/Sitemap.php');
$sitemap = new Sitemap;
if (get('pages')) {
$sitemap->page('pages');
$result = db_query ("SELECT url, created FROM pages"); // 20 pages
while (list($url, $created) = $result->fetch_row()) {
$sitemap->url($url, $created, 'yearly');
}
}
if (get('posts')) {
$sitemap->page('posts');
$result = db_query ("SELECT url, updated FROM posts"); // 70,000 posts
while (list($url, $updated) = $result->fetch_row()) {
$sitemap->url($url, $updated, 'monthly');
}
}
$sitemap->close();
unset ($sitemap);
function get ($name) {
return (isset($_GET['update']) && strpos($_GET['update'], $name) !== false) ? true : false;
}
?>
I would change this part....
if (get('pages')) {
$sitemap->page('pages');
$result = db_query ("SELECT uri FROM myuri");
while (list($url) = mysql_fetch_row($result)) {
$sitemap->url($url,'', 'yearly');
}
}
Not sure if that $updated is needed? Looks like the function just defaults it to an empty string anyways...... But maybe you could at a timestamp column to your table to pull the last updated date as well, and feed it into the function where I put ''.
Also....remove this part...
if (get('posts')) {
$sitemap->page('posts');
$result = db_query ("SELECT url, updated FROM posts"); // 70,000 posts
while (list($url, $updated) = $result->fetch_row()) {
$sitemap->url($url, $updated, 'monthly');
}
}