Location: PHPKode > scripts > QueryString > querystring.class.php
<?php
/**
 * QueryString: Helps build a query string for use in links.
 * Copyright (C) 2009 Dimitry Zolotaryov
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation; either version 2.1 of the License, or (at your option) 
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 * 
 * 
 * The QueryString class is a helper for building complex query strings. Useful
 * for the applications with many query parameters, the user can load a $_GET
 * into an instance of QueryString, modify the key/values and append the string
 * to a URL. The class can also be used in creating a POST request's body and
 * specialized query string, like those found in CakePHP. 
 * 
 * Use:
 *  echo qs( array('key' => 'value') )->add('key2', 'value2');
 *  // key=value&key2=value2
 * 
 * @author Dimitry Zolotaryov <hide@address.com>
 */
class QueryString {
	/**
	 * List of keys and values
	 * 
	 * @var array
	 */
	var $vars = array();
	/**
	 * Values to keep
	 * 
	 * @var array
	 */
	var $keep = array();
	/**
	 * Options used in formating
	 * 
	 * @var array
	 */
	var $options = array();
	/**
	 * The constructor.
	 * 
	 * Set the starting query string
	 * 
	 * @param $vars
	 * @return QueryString
	 */
	function QueryString( $vars, $options = array() ) {
		$options = array_merge( array(
			'kvsep'   => '=',
			'pairsep' => '&',
			'encode'  => 'rawurlencode',
			'subkey'  => '%key[%sub]'
		), $options);
		
		$this->options = $options;
		$this->vars = $vars;
	}
	/**
	 * Adds a key and value to the query string 
	 * 
	 * @param string $key The key
	 * @param mixed $value The value
	 * @return QueryString
	 */
	function add( $key, $value ) {
		if ( isset( $this->vars[ $key ] )) {
			if ( !is_array( $this->vars[ $key ] )) {
				$this->vars[ $key ] = array( $this->vars[ $key ] );
			}
			$this->vars[ $key ][] = $value;
		} else {
			$this->set( $key, $value );
		}
		return $this;
	}
	/**
	 * Replaces the value of a key with $value
	 * 
	 * @param string $key The key
	 * @param string $value The value
	 * @return QueryString
	 */
	function set( $key, $value ) {
		$this->vars[ $key ] = $value;
		return $this;
	}
	/**
	 * Removes a key from the query string
	 * 
	 * @param string $key
	 * @return QueryString
	 */
	function rem( $key ) {
		if ( isset( $this->vars[ $key ] )) {
			unset( $this->vars[ $key ] );
		}
		return $this;
	}
	/**
	 * Keeps only these query keys when building the string
	 * 
	 * @param string|array $keys The keys to keep
	 * @return QueryString
	 */
	function keep( $keys ) {
		if ( is_array( $keys )) {
			$this->keep = $keys;
		} else {
			$this->keep[] = $keys;
		}
		return $this;
	}
	/**
	 * Function returns a string representation of the query string
	 * 
	 * @return string
	 */
	function __toString() { 
		$kept = array_keys( $this->vars );
		if ( !empty( $this->keep )) {
			$kept = array_intersect( $kept, $this->keep );
		}
		$kept = array_unique( $kept );
		$qss = array();
		foreach ( $kept as $key ) {
			$value = $this->vars[ $key ];
			$this->__appendToQS( $key, $value, $qss );
		}
		
		return join( $this->options['pairsep'], $qss );
	}
	/**
	 * Appends the key and value to the passed query string array
	 * 
	 * @param string $key
	 * @param mixed $value
	 * @param array $querystring
	 */
	function __appendToQS( $key, $value, &$querystring ) {
		if ( is_array( $value )) {
			foreach ( $value as $k => $v ) {
				$newkey = str_replace(
					array('%key', '%sub'),
					array( $key , $k ),
					$this->options['subkey']
				);
				$this->__appendToQS( $newkey, $v, $querystring );
			}
		} else {
			if ( $this->options['encode'] ) {
				$key   = $this->options['encode']( $key );
				$value = $this->options['encode']( $value );
			}
			$querystring[] = $key . $this->options['kvsep'] . $value;
		}
	}
	/**
	 * Returns the string for this QueryString
	 * 
	 * @return string
	 */
	function string() {
		return $this->__toString();
	}
	/**
	 * Function to test this class
	 * 
	 */
	static function test() {
		
		echo "Starting the test\n";
		
		$qs = new QueryString(array('key' => 'value'));
		assert( $qs->string() == 'key=value' );
		
		$qs = new QueryString(array('key' => 'value'));
		$qs->add('key2', 'value2');
		assert( $qs->string() == 'key=value&key2=value2');
		
		$qs = new QueryString(array('key' => 'value'));
		$qs->add('key', 'value2');
		assert( $qs->string() == 'key%5B0%5D=value&key%5B1%5D=value2');
		
		$qs = new QueryString(array('key is' => 'value'));
		assert( $qs->string() == 'key%20is=value');
		
		$qs = new QueryString(array(
			'cities' => array('Miami', 'Montreal'),
			'people' => array(
				'male'   => array('John', 'Mike'),
				'female' => array('Jane', 'Michelle')
			)
		));
		assert( $qs->string() ==
			'cities%5B0%5D=Miami&cities%5B1%5D=Montreal&'
			. 'people%5Bmale%5D%5B0%5D=John&people%5Bmale%5D%5B1%5D=Mike&'
			. 'people%5Bfemale%5D%5B0%5D=Jane&people%5Bfemale%5D%5B1%5D=Michelle'
		);
		
		$qs = qs( array('key' => 'value', 'key2' => 'value' ) )->keep('key2');
		assert( $qs->string() == 'key2=value' );
		
		// cake php
		$qs = new CakeQueryString( array('key' => 'value', 'key2' => 'value2') );
		
		echo "Test completed\n";
	}
}

/**
 * A QueryString builder for use in CakePHP
 * 
 */
class CakeQueryString extends QueryString {
	/**
	 * Default constructor
	 * 
	 * @param string $vars
	 * @param array $options
	 */
	function CakeQueryString( $vars, $options = array() ) {
		$options = array_merge( array(
			'kvsep'   => ':',
			'pairsep' => '/'
		), $options );
		return parent::QueryString( $vars, $options );
	}
}

/**
 * Function for building a quick query string
 * 
 */
if ( !function_exists('qs')) {
	function qs( $params ) {
		return new QueryString( $params );
	}
}

// testing implementation
// > php querystring.class.php
if ( !empty( $argc ) && strstr( $argv[0], basename( __FILE__ )) ) {
	
	function assert_failure( $file, $line, $code ) {
		echo "Assertion failed (line $line): $code \n";
	}
	
	ini_set('error_reporting', E_ALL);
	error_reporting( E_ALL );
	
	assert_options( ASSERT_CALLBACK, 'assert_failure' );
	QueryString::test();
}
Return current item: QueryString