vector88/webutils

PHP tools to make working with things like HTTP requests and XML quick and easy.

1.0.9 2016-06-12 11:19 UTC

This package is not auto-updated.

Last update: 2024-11-23 20:42:10 UTC


README

Overview

The Web Utilities package is intended to provide some utilities to make common web-related operations quick and easy to perform.

The package currently contains helpers for:

  • XML generation and parsing
  • HTTP request generation and response parsing

This package is set up for integration with Composer and Laravel, but you can just as easily download and use the heavy-lifting classes independently.

Installation

  1. Execute composer require vector88/webutils to include webutils in your composer project.

Configuration

If you want to use this package with Laravel, you will need to add some entries to your config/app.php file to make use of the providers and facades:

<?php

'providers' => [
    ...
    Vector88\WebUtils\Providers\WebUtilsServiceProvider::class,
    ...
],

'aliases' => [
    ...
    'XmlHelper'          => Vector88\WebUtils\Facades\XmlHelper::class,
	'HttpRequestHelper'  => Vector88\WebUtils\Facades\HttpRequestHelper::class,
    ...
],

If you're not using this with Laravel, all you need to do is include the PHP files you'd like to use! you can do this using the autoload script, or through direct inclusion.

<?php

require __DIR__ . "/vendor/autoload.php";

use Vector88\WebUtils\XmlHelper;
use Vector88\WebUtils\HttpRequestHelper;

Usage

HTTP Request Helper

The HTTP Request Helper is designed to make HTTP requests trivial, for requests that live somewhere in complexity between file_get_contents and curl_setopt, which is where many APIs seem to sit.

Here's an example that showcases most of the features:

<?php

// Build a request (using Laravel with IOC)
$request = HttpRequestHelper::uri( $uri )
  ->authUsername( 'user' )
  ->authPassword( 'password' )
  ->method( 'POST' )
  ->header( 'Content-type', 'text/plain' )
  ->header( 'Cache-control', 'no-cache' )
  ->body( "Hello World! Here's some data..." );

// Execute the request
$response = $request->execute();

// If the request was successful:
if( $response->success ) {

  // Display the response code
  echo "{$response->code}<br />";

  // Display the response headers
  foreach( $response->headers as $header ) {
    echo "$header<br />";
  }

  // Display the response body
  echo "<br />";
  echo $response->body;

// Otherwise, if the request failed then display the error message and code
} else {
  echo "Request failed: {$response->errstr} ({$response->errno}).";

}

If you're not using Laravel, building the request changes a tiny bit:

<?php

// Build a request (not using Laravel)
$request = new HttpRequestHelper();
$request->uri( $uri )
  ...

XML Helper

The XML Helper is designed to make easy work of XML objects. At the document level, it's able to:

  • Load existing DOMDocument instances
  • Create new XML trees
  • Parse XML strings
  • Output XML strings

At the node level, there are a number of methods available to make reading and writing nodes trivial. On the reading level, there are also methods to work with collections of nodes.

Heads up: most stuff simply returns NULL if it can't get a value.

Using the XML Helper

If you are using the XML Helper with Laravel, you can take advantage of the IOC mechanisms.

<?php
$xml = XmlHelper::loadStream( $xmlString );
...

If you are using the XML Helper outside of Laravel, you can just create a new instance and work with the methods from there.

<?php
$xml = new XmlHelper();
$xml->loadStream( $xmlString );
...

Loading an XML String

<?php

// Load an XML String (using Laravel with IOC)
$xml = XmlHelper::loadStream( $xmlString );

Using an Existing DOMDocument

<?php

// Load a DOMDocument
$xml = XmlHelper::setElement( $document );

If you have a DOMNode that is attached to a DOMDocument, you can also do this to treat the DOMNode as the "root element" for many of the operations that the XmlHelper can perform:

<?php

// Load a DOMNode
$xml = XmlHelper::setElement( $node );

Creating a new XML object

<?php

// Create an empty XML object (with a document element)
$xml = XmlHelper::create();

Finding Elements

Say we have the following XML loaded into an XmlHelper instance named $xml:

<?xml version="1.0" encoding="utf-8"?>
<catalogue>
  <books>
    <book isbn="9780582186552">
      <title>Hobbit, The</title>
      <author>Tolkien, J. R. R.</author>
      <year>1937</year>
    </book>
    <book isbn="9780718179465">
      <title>Rachel Khoo's Kitchen Notebook</title>
      <author>Khoo, R.</author>
      <year>2015</year>
    </book>
  </books>
</catalogue>

Retrieving Individual Elements

The following code could be used to retrieve the <catalogue> node (as a DOMNode instance):

<?php
$catalogue = $xml->findFirst( 'catalogue' );

As the XmlHelper mostly backs on to DOMXPath, it's entirely possible to provide an XPath string. To retrieve the first book element...

<?php
$book = $xml->findFirst( '//book' );

Because XPath is XPath is XPath, you can retrieve the same element a million ways:

<?php
$book = $xml->findFirst( '/catalogue/books/book' );
$book = $xml->findFirst( '//books/book[starts-with(@isbn, "97805")]' );
$book = $xml->findFirst( '/catalogue//book[contains(author, "kien")]' );
...

Retrieving Collections of Elements

I'm sure you knew that when you saw findFirst there might also be a findAll method.

<?php
$books = $xml->findAll( '//books' );

Again, this method retrieves the DOMNode entries corresponding to the elements that are retrieved.

Retrieving an XmlHelper for Elements

If you'd rather retrieve an XmlHelper instance for the element you're searching for, you can get one directly by using the helper() method:

<?php
$catalogueHelper = $xml->helper( 'catalogue' );

Note that the helper() method doesn't quite operate the same as the findX() methods: it actually prepends ./ to the XPath before it's processed. This is handy because everything is relative to the current element, but if you're trying to do other stuff, it's bad, because everything is relative to the current element.

The reason that ./ is prepended is that it allows the helper to be re-used at a sub-node level - that is to say, all element queries will always be relative to the current DOMNode, rather than the root of the DOMDocument.

For example:

<?php
// GOOD. Do this.
$bookHelper = $xml->helper( 'catalogue/books/book' );

// OK. Because './' gets prepended, this is actually acceptable.
$bookHelper = $xml->helper( '/book' );

// BAD. Don't do this.
$bookHelper = $xml->helper( ''//book' );

Retrieving multiple XmlHelper Instances for Elements

It is also possible to retrieve an array of XmlHelper instances for a corresponding collection of DOMNode...

<?php
$bookHelpers = $xml->helpers( 'catalogue/books/book' );

Retrieving Element Values

This is where the useful stuff is in this library. If you have an XmlHelper instance wrapped around one of the <book /> elements listed above, you can use some helper methods to retrieve the node values.

<?php
// Retrieve a helper for the first book element that can be found
$book = $xml->helper( '/book' );

// Retrieve and display the book title and year
echo "Book Title: " . $book->string( "title" ) . "<br />";
echo "Year: " . $book->integer( "year" ) . "<br />";

If you want to do things in one fell swoop, you can make use of the wonders of XPath and target the element indirectly.

<?php
$title = $xml->string( '/book/title' );
$year = $xml->integer( '/book/year' );

In addition to string() and integer(), there is also float() which will retrieve a floating point value, and dateTime() which will retrieve (you guessed it) a DateTime element. the call to dateTime() requires a second argument, which is the date format string. This format string is the same as what would be used in DateTime::createFromFormat(), so look it up if you're not sure what to put in there.

Retrieving Multiple Element Values

There are also array versions of the above functions which allows you to get an array of values of the given type from all nodes that match the given XPath.

<?php
$allBookTitles = $xml->strings( '/book/title' );
$allBookYears = $xml->integers( '/book/year' );

Same goes for floats() and dateTimes().

Retrieving Attribute Values

It's probably what you'd expect:

<?php
$book = $xml->helper( '/book' );
$isbn = $book->stringAttribute( 'isbn' );

Also available: integerAttribute() and floatAttribute().

DOM Manipulation

There are only a few simple methods here as it's not really part of the original purpose of this package (but you're welcome to expand upon it!)

<?php
$booksHelper = $xml->helper( '/catalogue/books' );

// Add (and get) a new book element to the books element
$newBookHelper = $booksHelper->add( 'book' );

// Use the XML helper to set some attributes and add additional children
$newBookHelper->setAttribute( 'isbn', '9780764555893' );
$newBookHelper->add( 'title', 'PHP and MySQL for Dummies' );
$newBookHelper->add( 'author', 'Valade, J' );
$newBookHelper->add( 'year', '2002' );

XML String Generation

Use the toString() method to generate an XML string from the underlying document. Note that the XML will be generated from the "root node" of the helper that you're using.

<?php
$xmlString = $xml->toString();

TODO: Add a way for you to retrieve the underlying element, the root element, or a helper for one of those things, so you can get back to the root element somehow.

Namespace Integration

The XML Helper is able to work with elements in namespaces. Simply declare a namespace, and then use your namespace prefix to work with the elements in that namespace.

<?php
$xml = XmlHelper::loadStream( $xmlString );
$xml->withNamespace( "http://example.com/animals", "ns" );
$animals = $xml->findAll( "ns:animals/ns:animal" );

When using an XML Helper to generate an XML Helper for a child or children, namespaces are cloned and passed on at the time of generation, so you don't need to redeclare namespaces for subsequent calls.

<?php
$animalHelpers = $xml->helpers( "ns:animals/ns:animal" );
foreach( $animalHelpers as $animalHelper ) {
  echo $animalHelper->string( "ns:species" ) . "<br />";
  echo $animalHelper->string( "ns:subspecies" ) . "<br />";
}

Great, but I can do all of this stuff using DOMDocument and DOMXPath...

To be fair, this helper is just a front for DOMDocument and DOMXPath, but I made it because I'm lazy (ironic, I know).