PHP Archive

I just started diving into Zend Framework 2 after using Zend Framework 1 and even its early predecessors for years.
And boy, things have changed! But after some initial reading I think I already see some major advantages, not in the last place the ModuleManager which really allows developers to create independent modules and share them with the community.

Anyway on to the actual subject of this post: directory structure. A standard ZF2 application has the following directory structure:

config
data
module
public
vendor
init_autoloader.php

public contains index.php and your .htaccess, plus your public web resources such as images javascript and css files.

In a shared hosting environment running Plesk the directory structure is like this:

httpdocs (this is the webroot)
private
statistics
subdomains
etc.

We don’t want to put everything in the httpdocs directory, because that’s the public directory and is accessible from the outside world. In a Plesk environment the private directory is used for application level files that aren’t supposed to be accessible from outside. So the solution is pretty simple:

  • Upload the contents from the public directory into httpdocs
  • Upload the other directories (config, data, module, vendor and init_autoloader.php) into private

After that you have to change the index.php file (in public) to make sure it searches for the init_autoloader.php script in the right location. By default this is sitting at the same level as the public directory, outside the public directory and hence this statement at the top of index.php:

chdir(dirname(__DIR__));

This line should be changed into:

chdir(dirname(__DIR__) . '/private');

And that’s it, now your ZF2 app should run within this Plesk style directory structure. Pretty easy, but I hope it’s helpful to someone.

For a recent project I needed to use RSA encryption to encrypt some sensitive data that was being sent from a client to a (JSON) service. Both the client and the service are written in PHP using Zend Framework, so the obvious place to look for classes implementing this functionality is… well the Zend Framework library of course.

I was happily surprised finding the class Zend_Crypt_Rsa in the Crypt folder of the Zend Framework. When I wanted to check the online documentation at http://framework.zend.com/manual/en I was less happy, because it turns out there is no documentation for this class. Luckily it’s really not that hard to use. If you check out the code of the class itself it’s pretty self explanatory. However to save someone else some time it might be useful to post the steps I took to get it working, so here we go.

1. First of all you will need to have OpenSSL installed and the openssl PHP extension loaded, because the Zend_Crypt_Rsa class is dependent on it.

2. You have to generate the private and public keys that you’re going to use for the encryption (public key) and decryption (private key). You do this using the ssh-keygen command:

bender:~ ruben$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/ruben/.ssh/id_rsa): id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in id_rsa.
Your public key has been saved in id_rsa.pub.
The key fingerprint is:
e4:ec:fc:ae:b4:8e:6a:b0:85:6e:1f:72:58:56:ec:1e ruben@bender
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|     .           |
|      o .        |
|     o +         |
|   .o E S        |
|  o+.. +         |
| .o+o . +        |
|  +o.. o o       |
| . oo...+oo      |
+-----------------+
bender:~ ruben$

As you can see you have to specify a passphrase, note that this should be longer than 4 characters.
At this point you should have two files: id_rsa – the private key and id_rsa.pub – the public key.

3. Now move those two files to a folder inside your project, *outside* of the webroot(!), for instance “keys”.

4. Now you’re ready to encrypt something. Here’s a small example:

  1. 	$crypt = new Zend_Crypt_Rsa(array("passPhrase"=>"mypassphrase", "pemPath"=>"../keys/id_rsa"));
  2. 	$authString = $crypt->encrypt('secretword', $crypt->getPublicKey(), Zend_Crypt_Rsa::BASE64);

What this does is encrypt the word ‘secretword’ using your public key (located at ../keys/id_rsa). Note that the passPhrase parameter of the constructor should match the passphrase you used to create the keys. The output of the encryption will be in Base64 format. You can also choose to use binary (Zend_Crypt_Rsa::BINARY), but that’s less convenient for transferring purposes.

5. Decrypting is just as simple:

  1. 	$crypt = new Zend_Crypt_Rsa(array("passPhrase"=>"mypassphrase", "pemPath"=>"../keys/id_rsa"));	
  2. 	$decrypted = $crypt->decrypt($encryptedString, $crypt->getPrivateKey(), Zend_Crypt_Rsa::BASE64);

In this case the variable $encryptedString contains a Base64 string representing a previously encrypted string.

That’s all there’s to it, pretty easy right?

Be the first to comment

Datamapper pattern in PHP

Posted September 19, 2011 By ruben

The object-relational gap is a general problem in every OO programming language. Since PHP joined the OO club a while ago this problem also came along with it.

What I mean by object relational gap is the difference between a row in a relational database and an object in an OO language. Even though they have a lot in common, they aren’t the same thing and an OO programmer has to solve this by mapping rows to real objects. In an ideal world a programmer would only be concerned about objects and not database queries (and all the details that come with it) and many smart people have been trying to find the perfect solution to realize this. The result is many persistency frameworks that require the programmer to meta-tag class attributes to map them to database columns or write schemas to do the mapping. Some examples include JDO, JPA, (N)Hibernate, PDO and so on. In my opinion at this moment Microsoft offers the best solution with Linq, because it truly became part of the programming language and the programmer only has to deal with objects, while syntax checking happens at programming/compile time instead of runtime. Hopefully other languages (including PHP will follow), but for now we have to suffice with other solutions.

One of those solutions is the Datamapper design pattern which can be applied in every OO language. The UML schema (may) look like this:

In this example we have a class called UserMapper which has the responsibility to retrieve and store User objects. So basically it handles the mapping of a database row(s) to a User object. The different findBy* methods perform a SELECT query to find matching rows and then use the create(from the abstract superclass) and populate methods to create an object and fill it with the retrieved data.

The save method in the abstract superclass usually checks whether the id attribute of $obj has a value. If not it calls the private implementation of _insert and otherwise _update. Those specifics are up to you as the programmer/architect, but the main idea here is to keep the datamapping logic separated from the (business)logic, which is a good thing. If you want to get real fancy you can add an extra layer, often called the Gateway layer, which contains the actual database queries. You pass a gateway object (i.e. UserGateway) into the mapper class and just have the mapper class call the gateway instance to perform the database queries. In that case the schema would look more like this:

In this scenario you could switch one gateway layer for another, for instance if you want to support a different type of database.

Anyway the version without the extra gateway layer would like something like this in PHP (using Zend_Db for the database adapter):

MapperAbstract:

abstract class MapperAbstract
{
    /**
      * @var Zend_Db_Adapter_Pdo_Mysql
     */
    private $dbAdapter;
 
    /**
     * Create a new instance of the domain object. If the $data parameter is specified
     * then the object will be populated with it.
     * @param array $data
     * @return DomainObjectAbstract
     */
    public function create(array $data = null)
    {
        $obj = $this->_create();
        if ($data)
        {
            $obj = $this->populate($obj, $data);
        }
        return $obj;
    }
 
    /**
     * Save the domain object
     *
     * @param DomainObjectAbstract $obj
     */
    public function save(Application_Model_Abstract $obj)
    {
        if (is_null($obj->getId()))
        {
            $this->_insert($obj);
	}
	else
	{
            $this->_update($obj);
        }
    }
 
    /**
     * Delete the domain object
     * @param DomainObjectAbstract $obj
     */
    public function delete(Application_Model_Abstract $obj)
    {
        $this->_delete($obj);
    }
 
    /**
     * Populate the domain object with the values from the data array.
     *
     * @param DomainObjectAbstract $obj
     * @param array $data
     * @return DomainObjectAbstract
     */
    abstract public function populate(Application_Model_Abstract $obj, array $data);
 
    /**
     * Create a new instance of a domain object
     *
     * @return DomainObjectAbstract
     */
    abstract protected function _create();
 
    /**
     * Insert the domain object into the database
     *
     * @param DomainObjectAbstract $obj
     */
    abstract protected function _insert(Application_Model_Abstract $obj);
 
    /**
     * Update the domain object in persistent storage
     *
     * @param DomainObjectAbstract $obj
     */
    abstract protected function _update(Application_Model_Abstract $obj);
 
    /**
     * Delete the domain object from peristent Storage
     *
     * @param DomainObjectAbstract $obj
     */
    abstract protected function _delete(Application_Model_Abstract $obj);
}

UserMapper:

class UserMapper extends MapperAbstract
{
	private $dbAdapter;
 
	public function __construct($dbAdapter)
	{
		$this->dbAdapter = $dbAdapter;
	}
 
	/**
	* Create a new User domainobject
	*/
	protected function _create()
	{
		return new User();
	}
 
	/**
    * Insert the DomainObject in persistent storage
    *
    * @param DomainObjectAbstract $obj
	*/
	protected function _insert(DomainAbstract $obj)
	{
		// Insert User object into database
		/* @var $obj Application_Model_User */
		$query = 'INSERT INTO users (username,password) VALUES (?,SHA1(?))';
		$ret = $this->dbAdapter->query($query, array($obj->getUsername(),
								$obj->getPassword())
                );
 
		// Assign the new user id to the User object
		$obj->setId($this->dbAdapter->lastInsertId());
	}
 
	/**
	* Update
	*
	* @param DomainObjectAbstract $obj
	*/
	protected function _update(DomainAbstract $obj)
	{
		// Update User object in database
			$query = 'UPDATE users SET username=?,password=SHA1(?) WHERE id=?';
			$ret = $this->dbAdapter->query($query, array($obj->getUsername(),
									$obj->getPassword(),
									$obj->getId()
							));
	}
 
	/**
	* Delete the User from the database
	*
	* @param DomainObjectAbstract $obj
	*/
	protected function _delete(DomainAbstract $obj)
	{
		$query = 'DELETE FROM users WHERE id=?';
		$ret = $this->dbAdapter->query($query, array($obj->getId()));
    }
 
	/**
	* Populate the User (DomainObject) with the data array.
	*
	* @param DomainObjectAbstract $obj
	* @param array $data
	* @return User
	*/
	public function populate(DomainAbstract $obj, array $data)
	{
		if (isset($data['id']))
		{
			$obj->setId($data['id']);
		}
 
		if (isset($data['username']))
		{
			$obj->setUsername($data['username']);
		}
 
		if (isset($data['password']))
		{
			$obj->setPassword($data['password']);
		}
 
		return $obj;
	}
 
 
	/**
	 * Retrieves user by userid
	 * 
	 * @param int $userId
	 * @return User (null if not found)
	 */
	public function findById($userId)
	{
		$sql = "SELECT id,username,password FROM users WHERE id=?";
 
		$data = $this->dbAdapter->fetchRow($sql, array($userId), Zend_Db::FETCH_ASSOC);
 
		$user = null;
 
		if ($data != false)
		{
			$user = $this->create($data);
		}
 
		return $user;
	}
 
	/**
	 * Retrieves user by username
	 * 
	 * @param string $username
	 * @return User (null if not found)
	 */
	public function findByUsername($username)
	{
		$sql = "SELECT id,username,password FROM users WHERE username=?";
 
		$data = $this->dbAdapter->fetchRow($sql, array($username), Zend_Db::FETCH_ASSOC);
 
		$user = null;
 
		if ($data != false)
		{
			$user = $this->create();
		}
 
		return $user;
	}
}

How to use this? To retrieve a user in this setup you have to instantiate a UserMapper object and then ask it to retrieve and create the user domain object for you.

$userMapper = new UserMapper($dbAdapter);
$user = $userMapper->findByUsername('ruben');

Notice how easy it becomes to retrieve a domain object this way. It keeps your business logic code from getting cluttered with dirty database and object mapping details. The same goes for storing the object into the database:

$userMapper = new UserMapper($dbAdapter);
$user = $userMapper->findByUsername('ruben');
$user->setPassword('newpassword');
$userMapper->save($user);

The UserMapper class will figure out whether it has to perform an insert or an update query and do all the hard work.

Hope this helps anyone.

Be the first to comment

Parsing XML using DOMDocument and DOMXpath

Posted September 6, 2011 By ruben

In many webprojects I need to parse XML files of different kinds and shapes. PHP offers the DOMDocument class and the SimpleXML extension to read, parse, query and create XML documents. I personally prefer using the DOMDocument class hierarchy to SimpleXML, because it’s more powerful and offers more functionality especially when it comes to creating XML documents.

To show some possibilities of those classes I will demonstrate how to use them to parse Excel XML data. Here’s a screenshot of a small demo Excel workbook (a fictive pricelist):

You can save any Excel file in Excel XML format using Save As… and selecting XML Spreadsheet 2003 (*.xml):

After saving it to an XML file, the XML will look like this:

I collapsed the first few elements, because I’m going to focus on parsing the actual Worksheet data in this example.
So lets say you’re interested in parsing the cell data of this Excel sheet. If you only want to perform simple queries on your XML document the DOMDocument methods will suffice. In this case where you only want to get all Cell elements you could use the getElementsByTagName method, i.e.:

$xmlFile = 'pricelist.xml';
$domDoc = new DOMDocument();
$domDoc->load($xmlFile);
$cells = $domDoc->getElementsByTagName('Cell');

After this the variable $cells will contain a DOMNodeList object, which is just a list of DOMNode objects which you can traverse.

If you want to perform more complicated queries on your XML document you could use XPath. XPath is an XML query language with a simple syntax and relatively powerful possibilities.

In PHP’s DOM class hierarchy we have the class DOMXPath to perform XPath queries. For example to do the same as the getElementsByTagName code above, we can perform this XPath query: //ss:Data
The double slash in that query means that it doesn’t matter where in the document the element ss:Data is located. This will simply fetch every single ss:Data element in the document. If you want to get specific elements, starting at the document root, you should use single slash syntax like this: /ss:Workbook/ss:Worksheet/ss:Table/ss:Row/ss:Cell/ss:Data.

Also note that I’m using the ss: prefix to tell XPath to look for elements in that namespace, which is the microsoft spreadsheet namespace in this case.

Executing a query using DOMXPath would go like this:

$xmlFile = 'pricelist.xml';
$domDoc = new DOMDocument();
$domDoc->load($xmlFile);
$xpath = new DOMXpath($domDoc);
 
$dataElems = $xpath->query('//ss:Data');
 
foreach ($dataElems as $curElem)
{
	echo $curElem->nodeValue . "\n";
}

The cool thing about XPath is that you can use filterqueries that are quite advanced. You can specify extra elementfilters in square brackets. For example to get all Row elements with exactly 3 Cell elements that contain a Data element in the above Excel XML, you could use a count filter like this:
//ss:Row[count(ss:Cell/ss:Data)=3]

$xmlFile = 'pricelist.xml';
$domDoc = new DOMDocument();
$domDoc->load($xmlFile);
$xpath = new DOMXpath($domDoc);
 
$rows = $xpath->query('//ss:Row[count(ss:Cell/ss:Data)=3]');
 
foreach ($rows as $curRow)
{
	// iterate through Cell elems
	foreach ($curRow->childNodes as $curCell)
	{
		// ...
	}
}

Basically these classes make parsing XML a walk in the park, that is if you know how to use them. I hope this brief introduction will help you to get you going.

12 Comments so far. Join the Conversation

New php_solr PECL extension for Windows

Posted September 1, 2011 By ruben

The new version (1.0.1) of the php_solr extension is available for download at: http://pecl.php.net/package/solr. Unfortunately there are no binaries available for Windows, so I decided to build it myself. I compiled a 32-bit non-threadsafe version for PHP 5.3.9, so if you are interested you can download it here: php_solr 1.0.1

Simply unpack it and put it in your php ext folder. Then add an extension=php_solr.dll in your php.ini and you are good to go.

 

3 Comments so far. Join the Conversation