Dirk Harriman Banner Image

 

PHP Notes - XML I/O


Notes On XML

XML Comments

Comments in XML is the same as with HTML: <!-- THIS IS A COMMENT -->.

CDATA

In an XML document or external entity, a CDATA section is a piece of element content that is marked up to be interpreted literally, as textual data, not as marked-up content. A CDATA section is merely an alternative syntax for expressing character data; there is no semantic difference between character data in a CDATA section and character data in standard syntax where, for example, "<" and "&" are represented by "&lt;" and "&amp;", respectively.
A CDATA section starts with <![CDATA[ and ends with ]]> all of the characters between these tags are interpreted as characters, not markup or entity references. Every character is taken literally, the only exception being the ]]> sequence of characters. In:

<sender>John Smith</sender> the start and end sender tags are interpreted as markup. However, the code: <![CDATA[<sender>John Smith</sender>]]> is equivalent to: &lt;sender&gt;John Smith&lt;/sender&gt;

Thus, the "tags" will have exactly the same status as the "John Smith"; they will be treated as text.

Use Of CDATA

Sometimes the data you need to store contains characters that would cause the interpreter to fail, such as the use of HTML tags.


PHP XML Classes

There are two primary classes that are used to deal with XML within the PHP language.


XML Data

The following is an example of what a login XML file might look like.

<?xml version="1.0" encoding="utf-8"?> <users> <user> <user_id>0</user_id> <user_status>1</user_status> <user_name>Dirk</user_name> <user_pass><![CDATA[$2y$10$E2oUiMYBv4AmStGPKQdgaOp/rWajplyveC8IYU56FFIhwAX.jRFAa]]></user_pass> <user_access>0</user_access> </user> <user> <user_id>1</user_id> <user_status>1</user_status> <user_name>Jack</user_name> <user_pass><![CDATA[$2y$10$obEgE/H6cyzDYfLYotUIIOaHM9WR7v5Aqu0fbrL5Z8OI.C1k4AD.2]]></user_pass> <user_access>1</user_access> </user> <user> <user_id>2</user_id> <user_status>0</user_status> <user_name>Sam</user_name> <user_pass><![CDATA[$2y$10$3d8ABp1yuDbPNsC4aNeqYefTaQPCYyr.JhK0zuSpOOX2AFEIGKUo.]]></user_pass> <user_access>1</user_access> </user> </users>


Simple XML

The SimpleXML extension provides a very simple and easily usable toolset to convert XML to an object that can be processed with normal property selectors and array iterators.

The SimpleXMLElement class

class SimpleXMLElement implements Stringable, Countable, RecursiveIterator { /* Methods */ public __construct( string $data, int $options = 0, bool $dataIsURL = false, string $namespaceOrPrefix = "", bool $isPrefix = false ) public addAttribute(string $qualifiedName, string $value, ?string $namespace = null): void public addChild(string $qualifiedName, ?string $value = null, ?string $namespace = null): ?SimpleXMLElement public asXML(?string $filename = null): string|bool public attributes(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement public children(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement public count(): int public current(): SimpleXMLElement public getDocNamespaces(bool $recursive = false, bool $fromRoot = true): array|false public getName(): string public getNamespaces(bool $recursive = false): array public getChildren(): ?SimpleXMLElement public hasChildren(): bool public key(): string public next(): void public registerXPathNamespace(string $prefix, string $namespace): bool public rewind(): void public __toString(): string public valid(): bool public xpath(string $expression): array|null|false }


Load XML with SimpleXML

simplexml_load_file( string $filename, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false ): SimpleXMLElement|false

... if (file_exists('login.xml')) { $xml = simplexml_load_file("login.xml") or die ("Cannot open XML file"); } else { // FILE DOES NOT EXIST }


Simple XML - Accessing XML Data

In the following file a entered password is compared to a stored password. The function used, password_verify(), checks the

<?php // GET THE POSTED DATA $txtUsername = $_POST['txtUsername']; $txtPassword = $_POST['txtPassword']; $error_str = ''; $info_str = ''; $access_level = -1; /* * XML STRUCTURE * * users * user user_id status access * user_name * user_pass */ if (file_exists('xml_users.xml')) { $xml = simplexml_load_file("users.xml") or die ("Cannot open XML file"); foreach($xml->children() as $users) { if ($txtUsername == $users->user_name) { if (password_verify($txtPassword, $users->user_pass)) { // START A SESSION session_start(); $access_level = (int)$users['access']; $_SESSION['access'] = (int)$users['access']; $_SESSION['sid'] = (int)$users['user_id']; $_SESSION['user_name'] = $txtUsername; break; } else { $error_str = "Incorrect Password"; break; } } } } else { $error_str = "File Does Not Exist"; } $output = array('errorString' => $errorStr, 'userName' => $txtUsername, 'accessLevel' => $access_level); header('Content-Type:application/json'); echo json_encode($output, JSON_FORCE_OBJECT); ?>

Simple XML - Modifying XML Data

if (file_exists('login.xml')) { $xml = simplexml_load_file("login.xml") or die ("Cannot open XML file"); foreach($xml->children() as $users) { if ($username == $users->user_name) { $users->user_status = 0; break; } } if ($xml->asXML('login.xml')) { echo 'File Saved'; } else { echo 'Unable to save to file'; } } else { // FILE DOES NOT EXIST }

Writing CDATA Using Simple XML

Simple XML does not have a method for specifically writing CDATA. A workaround is to create a class that extends the SimpleXMLElement.

class SimpleXMLExtended extends SimpleXMLElement { public function addCData($cdata_text) { $node= dom_import_simplexml($this); $no = $node->ownerDocument; $node->appendChild($no->createCDATASection($cdata_text)); } }

Simple XML - Creating XML Data

<?php class SimpleXMLExtended extends SimpleXMLElement { public function addCData($cdata_text) { $node= dom_import_simplexml($this); $no = $node->ownerDocument; $node->appendChild($no->createCDATASection($cdata_text)); } } /* * XML STRUCTURE * * users * user user_id status access * user_pass (CDATA) * */ if (file_exists('login.xml')) { $xml_t = simplexml_load_file('xml_users.xml') or die ('Cannot open XML file'); $sxe = new SimpleXMLExtended($xml_t->asXML()); $user = $sxe->addChild('user'); $user->addAttribute('user_id', 5); $user->addAttribute('status', 1); $user->addAttribute('access', 2); $user->user_pass = NULL; $user->user_pass->addCData(password_hash($txtPassword, PASSWORD_DEFAULT)); $sxe->asXML('login.xml'); }

<?php class SimpleXMLExtended extends SimpleXMLElement { public function addCData($cdata_text) { $node= dom_import_simplexml($this); $no = $node->ownerDocument; $node->appendChild($no->createCDATASection($cdata_text)); } } $txtUsername = $_POST['txtUsername']; $txtPassword = $_POST['txtPassword']; $info_str = ''; $access_level = 2; $error_str = ''; $counter = 0; /* * users * user user_id status access * user_name * user_pass */ if (file_exists('xml_users.xml')) { $info_str = 'File Exists. '; $xml_t = simplexml_load_file('xml_users.xml') or die ('Cannot open XML file'); $xml = new SimpleXMLExtended($xml_t->asXML()); // CHECK FOR EXISTING RECORD WITH ENTERED USERNAME foreach($xml->children() as $users) { $counter++; if ($txtUsername == $users->user_name) { $error_str = 'Error: Username Already Exists'; break; // EXIT THE FOR LOOP - NO NEED TO LOOK FURTHER } } if ($error_str == "") { $user = $xml->addChild('user'); $user->addAttribute('user_id',$counter); $user->addAttribute('status','1'); // ACTIVE $user->addAttribute('access','2'); // BASIC USER // USER_NAME $user->addChild('user_name', $txtUsername); // USER_PASS - NEED TO WRITE AS CDATA $user->user_pass = NULL; $user->user_pass->addCData(password_hash($txtPassword, PASSWORD_DEFAULT)); // SAVE XML TO FILE $xml->asXML('xml_users.xml'); $info_str .= 'User '. $txtUsername .' Added.'; } } else { $info_str = 'File Does Not Exist, Created'; /* FILE DOES NOT EXIST, SO CREATE XML TO BE SAVED TO FILE */ $domDoc = new DomDocument('1.0', 'UTF-8'); $domDoc->preserveWhiteSpace = false; $domDoc->formatOutput = true; // ADD ROOT ELEMENT $users = $domDoc->appendChild($domDoc->createElement('users')); // CREATE USER NODE $user = $domDoc->createElement('user'); $user->setAttribute( 'user_id', '0' ); // FIRST USER $user->setAttribute( 'status', '1' ); // ACTIVE $user->setAttribute( 'access', '2' ); // BASIC USER $user_name = $domDoc->createElement('user_name', $txtUsername); $user_pass = $domDoc->createElement('user_pass'); // USER_PASS $user_pass->appendChild($domDoc->createCDataSection(password_hash($txtPassword, PASSWORD_DEFAULT))); // APPEND USER_NAME TO USER $user->appendChild( $user_name ); // APPEND USER_PASS TO USER $user->appendChild( $user_pass ); // APPEND USER TO USERS $users->appendChild( $user ); // SAVE IN FILE "xml_users.xml" $domDoc->save('xml_users.xml'); } $output = array('errorString' => $error_str, 'infoString' => $info_str, 'userName' => $txtUsername, 'accessLevel' => $access_level); header('Content-Type:application/json'); echo json_encode($output, JSON_FORCE_OBJECT); ?>


DOM


Load XML File


Accessing XML Data


Modifying XML Data


Creating XML Data