Table of Contents
List of Figures
List of Examples
onGet
method)setWriterConfig
method)export
method)onPost
method)import
method)getConsumer
and onAuthenticated
method)onPost
method)Table of Contents
PSX is a framework for developing dynamic websites in PHP. The goal of PSX is to help you developing RESTful APIs serving web standard formats like JSON, XML, Atom and RSS. It has a focus on social technologies and provides classes to use and implement OAuth, OpenID, Opengraph, Opensocial, Opensearch, PubSubHubbub, Atom, and RSS. At the example page you can see sample implementations using various PSX classes wich give you an good overview how the PSX framework works. On the download section you can grab the current release of PSX or you can install it via PEAR. If you want contribute or get in contact you find at the community page all necessary informations. In the following a short overview what features PSX offers.
PSX offers a comprehensive PHP library wich is loosly coupled and designed after standard naming conventions so it can be used with other projects like i.e. PEAR, Symfony or Zend. All classes are independently usable because of dependency injection.
PSX supports you in building RESTful APIs using web standard formats like JSON, XML, Atom and RSS with standard request parameters like defined in the OpenSocial Core API Spec. To build a more programmable and federated social web.
First you must download the current version of psx. You can find that at phpsx.org. Download psx and put the dir on your web or local server. To run PSX you need PHP 5 or higher depending on what classes you use. Goto http://host/path/to/psx/public if you see a website with the title "Template sample" psx is running successfully.
Table of Contents
This is the main chapter of the manual wich explains step by step howto develop a RESTful API based on PSX. In this example we create a simple news API where you can create and receive news records.
For our example we need a simple table called news where all records are stored.
Example 3.1. news table
CREATE TABLE IF NOT EXISTS `news` ( `id` int(10) NOT NULL AUTO_INCREMENT, `author` varchar(32) NOT NULL, `title` varchar(128) NOT NULL, `body` text NOT NULL, `date` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Now we have to create the model for the News. The class must be created in the file library/Example/News.php.
The record must implement the PSX_Data_RecordInterface
in this case we use the class
PSX_Data_RecordAbstract
wich already implements the
PSX_Data_RecordInterface
and has some methods already implemented.
We only need to add the method getName
wich returns the name of the record and
getCols
wich returns an array with property names wich can be used. The setters
are used to import data into the record.
Example 3.2. library/Example/News.php
<?php class Example_News extends PSX_Data_RecordAbstract { public $id; public $author; public $title; public $body; public $date; private $config; public function __construct(PSX_Config $config) { $this->config = $config; } public function getName() { return 'news'; } public function getCols() { return array('id', 'author', 'title', 'body', 'date'); } public function setAuthor($author) { $author = htmlspecialchars($author); if(strlen($author) > 3 && strlen($author) < 32) { $this->author = $author; } else { throw new Exception('Author must greater then 3 and lower then 32 signs'); } } public function setTitle($title) { $title = htmlspecialchars($title); if(strlen($title) > 3 && strlen($title) < 64) { $this->title = $title; } else { throw new Exception('Title must greater then 3 and lower then 64 signs'); } } public function setBody($body) { $body = htmlspecialchars($body); if(strlen($body) > 6 && strlen($body) < 1024) { $this->body = $body; } else { throw new Exception('Body must greater then 6 and lower then 1024 signs'); } } public function getDate() { return new DateTime($this->date); } }
We create a file called news.php in the module folder. This file can be
accessed with http://127.0.0.1/psx/public/index.php/news. We define the onLoad
method
wich is called when the module was loaded. Because we need an SQL connection to retrieve and store the news
entries we create an PSX_Sql
object.
This is now the REST API endpoint where we can make GET and POST requests to. You can versioning your API by creating a folder structure i.e. put the news.php in the folder "v1" and the endpoint url would be http://127.0.0.1/psx/public/index.php/v1/news
Example 3.3. module/news.php
<?php
class news extends PSX_ApiAbstract
{
private $sql;
public function onLoad()
{
// create sql connection
$this->sql = new PSX_Sql(new PSX_Sql_Driver_Pdo(), $this->config['psx_sql_host'], $this->config['psx_sql_user'], $this->config['psx_sql_pw'], $this->config['psx_sql_db']);
}
}
If someone makes an GET request to the endpoint we want return
the latest news. This method creates in general an PSX_Data_ResultSet
object
containing multiple Example_News
objects. If we call the setResponse
method with the PSX_Data_ResultSet
object the object is transformed
into the preferred format (wich was set either by the GET parameter "format"
or by the "Accept" header field).
Example 3.4. module/news.php (implement onGet
method)
public function onGet() { // get default params $params = $this->getRequestParams(); // selected fields $availableFields = array('id', 'author', 'title', 'body', 'date'); $selectedFields = array(); if(isset($params['fields'])) { foreach($params['fields'] as $field) { if(in_array($field, $availableFields)) { $selectedFields[] = $field; } } } if(empty($selectedFields)) { $selectedFields = $availableFields; } // limit $startIndex = isset($params['startIndex']) ? $params['startIndex'] : 0; $count = isset($params['count']) ? $params['count'] : 8; // get complete count $totalResults = $this->sql->count('news'); // make query $sql = 'SELECT ' . implode(',', $selectedFields) . ' FROM news ORDER BY date DESC LIMIT ?, ?'; $result = $this->sql->getAll($sql, array($startIndex, $count), PSX_Sql::FETCH_OBJECT, 'Example_News', array($this->config)); // create resultset $resultset = new PSX_Data_ResultSet($totalResults, $startIndex, $count, $result); // set response $this->setResponse($resultset); }
Because we want create Atom and Rss feeds we have to
set the writer config by overriding the method setWriterConfig
.
Example 3.5. module/news.php (implement setWriterConfig
method)
protected function setWriterConfig(PSX_Data_WriterResult $writer) { switch($writer->getType()) { case PSX_Data_WriterInterface::RSS: $updated = $this->sql->getField('SELECT `date` FROM news ORDER BY `date` DESC'); $title = 'News'; $link = $this->config['psx_url']; $description = 'Example RESTful News API based on PSX '; $writer = $writer->getWriter(); $writer->setConfig($title, $link, $description); $writer->setGenerator('psx ' . $this->config['psx_version']); break; case PSX_Data_WriterInterface::ATOM: $updated = $this->sql->getField('SELECT `date` FROM news ORDER BY `date` DESC'); $title = 'News'; $id = $this->config->getUrn('psx', 'example', 'news'); $updated = new DateTime($updated); $writer = $writer->getWriter(); $writer->setConfig($title, $id, $updated); $writer->setGenerator('psx ' . $this->config['psx_version']); break; } }
Because we want that the record can be exported in different formats like JSON,
XML, Atom, Rss we have to specific the method
export
in the Example_News
record.
Example 3.6. library/Example/News.php (implement export
method)
public function export(PSX_Data_WriterResult $result) { switch($result->getType()) { case PSX_Data_WriterInterface::JSON: case PSX_Data_WriterInterface::XML: return $this->getFields(); break; case PSX_Data_WriterInterface::RSS: $title = $this->title; $link = $this->config['psx_url'] . '/' . $this->config['psx_dispatch'] . 'news/id/' . $this->id; $description = $this->body; $item = $result->getWriter()->createItem($title, $link, $description); $item->setAuthor($this->author); return $item; break; case PSX_Data_WriterInterface::ATOM: $title = $this->title; $id = $this->id; $date = $this->getDate(); $entry = $result->getWriter()->createEntry($title, $id, $date); $entry->addAuthor($this->author, $this->config->getUrn('user', $this->author)); $entry->addLink($this->config['psx_url'] . '/' . $this->config['psx_dispatch'] . 'news/id/' . $this->id, 'alternate', 'text/html'); $entry->setContent($this->body, 'text'); return $entry; break; default: throw new PSX_Data_Exception('Writer is not supported'); break; } }
Here an example GET request with the response
Example 3.7. Sample GET request
GET /test/psx/public/ HTTP/1.1 Host: 127.0.0.1 Accept: application/xml
Example 3.8. Sample GET response
HTTP/1.1 200 OK Date: Fri, 01 Jul 2011 22:50:11 GMT Server: Apache/2.2.12 (Win32) DAV/2 mod_ssl/2.2.12 OpenSSL/0.9.8k mod_autoindex_color PHP/5.3.0 mod_perl/2.0.4 Perl/v5.10.0 X-Powered-By: psx Expires: Thu, 09 Oct 1986 01:00:00 GMT Last-Modified: Thu, 09 Oct 1986 01:00:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 336 Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <resultset> <totalResults>1</totalResults> <startIndex>0</startIndex> <itemsPerPage>8</itemsPerPage> <entry> <id>1</id> <author>Foobar</author> <title>Some great title</title> <body>And much more great content ... hf ;D</body> <date>2011-06-30 22:15:51</date> </entry> </resultset>
If someone makes a POST request we want insert the news in
the table. We create a new Example_News
object and import the
request data into the record.
Example 3.9. module/news.php (implement onPost
method)
public function onPost() { try { $news = new Example_News($this->config); $news->import($this->getRequest()); if($news->hasFields('author', 'title', 'body')) { $news->date = date(PSX_Time::SQL); $this->sql->insert('news', $news->getData()); $msg = new PSX_Data_Message('News record successful created', true); $this->setResponse($msg, null, 201); } else { throw new Exception('Missing field in record'); } } catch(Exception $e) { $msg = new PSX_Data_Message($e->getMessage(), false); $this->setResponse($msg, null, 500); } }
Because we want import data into the Example_News
record we have
to specify the import
method. In this case we accept
application/x-www-form-urlencoded, application/json and
application/xml data. That means we can also use a web form pointing to the
API endpoint to insert new records.
Example 3.10. library/Example/News.php (implement import
method)
public function import(PSX_Data_ReaderResult $result) { switch($result->getType()) { case PSX_Data_ReaderInterface::FORM: case PSX_Data_ReaderInterface::JSON: case PSX_Data_ReaderInterface::XML: $data = (array) $result->getData(); $data = array_intersect_key($data, array_fill_keys($this->getCols(), null)); foreach($data as $k => $v) { if(isset($v)) { $method = 'set' . ucfirst($k); if(is_callable(array($this, $method))) { $this->$method($v); } } } break; default: throw new PSX_Data_Exception('Reader is not supported'); break; } }
Here an example POST request to the API endpoint
Example 3.11. Sample POST request
POST /test/psx/public/ HTTP/1.1 Host: 127.0.0.1 Accept: application/xml Content-type: application/xml Content-Length: 166 <?xml version="1.0" encoding="UTF-8"?> <news> <author>Foobar</author> <title>Some great title</title> <body>And much more great content ... hf ;D</body> </news>
Example 3.12. Sample POST response
HTTP/1.1 201 Created Date: Fri, 01 Jul 2011 22:51:38 GMT Server: Apache/2.2.12 (Win32) DAV/2 mod_ssl/2.2.12 OpenSSL/0.9.8k mod_autoindex_color PHP/5.3.0 mod_perl/2.0.4 Perl/v5.10.0 X-Powered-By: psx Expires: Thu, 09 Oct 1986 01:00:00 GMT Last-Modified: Thu, 09 Oct 1986 01:00:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 130 Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <message> <text>News record successful created</text> <success>true</success> </message>
This example has shown you howto build an API with PSX wich serves content in Atom, RSS, <porperty>Json</porperty> and XML on an GET request. Also it is possible to insert new records with a POST request. This API can be used by any other website or desktop application to build a more programmable web.
Table of Contents
It is often the case that you want that only registered users can POST new entries to the API endpoint. In this case the user has to authorize before submitting a new record. The current standard for API authorization is Oauth. PSX comes with a set of classes wich helps implementing OAuth authorization for your endpoint. At the moment PSX supports the Oauth 1.0 specification (http://tools.ietf.org/html/rfc5849) but we are working on implementing OAuth 2.0. In this chapter we will protect the news API wich we have developed in the chapter before with Oauth so that only user with a valid consumer key and consumer secret can POST news records.
In order to store the Oauth requests we use the following table
Example 4.1. request table
CREATE TABLE IF NOT EXISTS `request` ( `id` int(10) NOT NULL AUTO_INCREMENT, `ip` varchar(128) NOT NULL, `token` varchar(40) NOT NULL, `tokenSecret` varchar(40) NOT NULL, `nonce` varchar(32) NOT NULL, `verifier` varchar(16) DEFAULT NULL, `authorized` int(1) NOT NULL DEFAULT '0', `callback` varchar(256) DEFAULT NULL, `exchangeDate` datetime DEFAULT NULL, `authorizationDate` datetime DEFAULT NULL, `insertDate` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `token` (`token`), UNIQUE KEY `tokenSecret` (`tokenSecret`), UNIQUE KEY `nonce` (`nonce`), UNIQUE KEY `verifier` (`verifier`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
In order to enable Oauth authentication we have to implement the following endpoints like defined in the specification.
Endpoint | Location |
---|---|
Temporary Credential Request | http://127.0.0.1/psx/public/index.php/request |
Resource Owner Authorization | http://127.0.0.1/psx/public/index.php/auth |
Token Request | http://127.0.0.1/psx/public/index.php/access |
This endpoint is for obtaining an temporary credential.
Example 4.2. module/request.php
<?php
class request extends PSX_Oauth_Provider_RequestAbstract
{
private $sql;
public function onLoad()
{
try
{
$this->sql = new PSX_Sql(new PSX_Sql_Driver_Pdo(), $this->config['psx_sql_host'], $this->config['psx_sql_user'], $this->config['psx_sql_pw'], $this->config['psx_sql_db']);
// if we call the handle method the OAuth request is proccessed and
// the getConsumer() and getResponse() method is called
$this->handle();
}
catch(Exception $e)
{
header('HTTP/1.1 500 Internal Server Error');
echo $e->getMessage();
if($this->config['psx_debug'] === true)
{
echo "\n\n" . $e->getTraceAsString();
}
exit;
}
}
protected function getConsumer($consumerKey)
{
if($consumerKey == $this->config['consumer_key'])
{
return new PSX_Oauth_Provider_Data_Consumer($this->config['consumer_key'], $this->config['consumer_secret']);
}
else
{
throw new PSX_Oauth_Exception('Invalid consumer key');
}
}
protected function getResponse(PSX_Oauth_Provider_Data_Consumer $consumer, PSX_Oauth_Provider_Data_Request $request)
{
// generate tokens
$token = sha1(uniqid(mt_rand(), true));
$tokenSecret = sha1(uniqid(mt_rand(), true));
// insert request
$this->sql->insert('request', array(
'ip' => $_SERVER['REMOTE_ADDR'],
'token' => $token,
'tokenSecret' => $tokenSecret,
'nonce' => $request->getNonce(),
'callback' => $request->getCallback(),
'insertDate' => date(PSX_Time::SQL),
));
// return response
$response = new PSX_Oauth_Provider_Data_Response();
$response->setToken($token);
$response->setTokenSecret($tokenSecret);
return $response;
}
}
If the Oauth client has obtained the temporary credential the user will be redirected to the Resource Owner Authorization endpoint.
Example 4.3. module/auth.php
<?php class auth extends PSX_ModuleAbstract { private $sql; public function onLoad() { $this->sql = new PSX_Sql(new PSX_Sql_Driver_Pdo(), $this->config['psx_sql_host'], $this->config['psx_sql_user'], $this->config['psx_sql_pw'], $this->config['psx_sql_db']); $token = isset($_GET['oauth_token']) ? $_GET['oauth_token'] : null; if(!empty($token)) { $row = $this->sql->getRow('SELECT id, ip, token, authorized, callback, insertDate FROM request WHERE token = ?', array($token)); if(!empty($row)) { // validate if($_SERVER['REMOTE_ADDR'] != $row['ip']) { throw new Exception('Token was requested from another ip'); } if($row['authorized'] != 0) { throw new Exception('Token was already authorized'); } // @todo check the insertDate whether token is expired // generate verifier $verifier = substr(sha1(uniqid(mt_rand(), true)), 0, 16); // update request $con = new PSX_Sql_Condition(array('id', '=', $row['id'])); $this->sql->update('request', array( 'verifier' => $verifier, 'authorized' => 1, 'authorizationDate' => date(PSX_Time::SQL), ), $con); // redirect user or display verifier if($row['callback'] != 'oob') { $url = new PSX_Url($row['callback']); $url->addParam('oauth_token', $row['token']); $url->addParam('oauth_verifier', $verifier); header('Location: ' . strval($url)); exit; } else { echo '<p>You have successful authorized a token. Please provide the following verifier to your application in order to complete the authorization proccess.</p>'; echo '<p>Verifier:</p><p><b>' . $verifier . '</b></p>'; } } else { throw new Exception('Invalid token'); } } else { throw new Exception('Token not set'); } } }
Example 4.4. module/access.php
<?php class access extends PSX_Oauth_Provider_AccessAbstract { private $sql; private $id; private $nonce; private $verifier; public function onLoad() { try { $this->sql = new PSX_Sql(new PSX_Sql_Driver_Pdo(), $this->config['psx_sql_host'], $this->config['psx_sql_user'], $this->config['psx_sql_pw'], $this->config['psx_sql_db']); // if we call the handle method the OAuth request is proccessed and // the getConsumer() and getResponse() method is called $this->handle(); } catch(Exception $e) { header('HTTP/1.1 500 Internal Server Error'); echo $e->getMessage(); if($this->config['psx_debug'] === true) { echo "\n\n" . $e->getTraceAsString(); } exit; } } protected function getConsumer($consumerKey, $token) { if($consumerKey == $this->config['consumer_key']) { $row = $this->sql->getRow('SELECT id, nonce, verifier, token, tokenSecret FROM request WHERE token = ? AND authorized = 1', array($token)); if(!empty($row)) { $this->id = $row['id']; $this->nonce = $row['nonce']; $this->verifier = $row['verifier']; return new PSX_Oauth_Provider_Data_Consumer($this->config['consumer_key'], $this->config['consumer_secret'], $row['token'], $row['tokenSecret']); } else { throw new PSX_Oauth_Exception('Invalid token'); } } else { throw new PSX_Oauth_Exception('Invalid consumer key'); } } protected function getResponse(PSX_Oauth_Provider_Data_Consumer $consumer, PSX_Oauth_Provider_Data_Request $request) { // validate if($this->nonce == $request->getNonce()) { throw new PSX_Oauth_Exception('Nonce hasnt changed'); } if($this->verifier != $request->getVerifier()) { throw new PSX_Oauth_Exception('Invalid verifier'); } // generate a new access token $token = sha1(uniqid(mt_rand(), true)); $tokenSecret = sha1(uniqid(mt_rand(), true)); // update request $con = new PSX_Sql_Condition(array('id', '=', $this->id)); $this->sql->update('request', array( 'authorized' => 2, 'token' => $token, 'tokenSecret' => $tokenSecret, 'exchangeDate' => date(PSX_Time::SQL), ), $con); // return response $response = new PSX_Oauth_Provider_Data_Response(); $response->setToken($token); $response->setTokenSecret($tokenSecret); return $response; } }
The class news
has to extend the class
PSX_Oauth_ProviderAbstract
instead of PSX_ApiAbstract
Example 4.5. module/news.php (implement getConsumer
and onAuthenticated
method)
protected function getConsumer($consumerKey, $token) { if($consumerKey == $this->config['consumer_key']) { $row = $this->sql->getRow('SELECT token, tokenSecret FROM request WHERE token = ? AND authorized = 2', array($token)); if(!empty($row)) { return new PSX_Oauth_Provider_Data_Consumer($this->config['consumer_key'], $this->config['consumer_secret'], $row['token'], $row['tokenSecret']); } else { throw new PSX_Oauth_Exception('Invalid token'); } } else { throw new PSX_Oauth_Exception('Invalid consumer key'); } } protected function onAuthenticated() { $this->isAuthed = true; }
Now we have to check for an Authentication header if a POST request
was made. If we call the handle
method wich is defined by the class
PSX_Oauth_ProviderAbstract
we check whether it is a valid Oauth request.
Example 4.6. module/news.php (implement onPost
method)
public function onPost() { try { // check for oauth authentication $this->handle(); if(!$this->isAuthed) { throw new PSX_Exception('Not authenticated', 401); } // create news record $news = new Example_News($this->config); $news->import($this->getRequest()); if($news->hasFields('author', 'title', 'body')) { $news->date = date(PSX_Time::SQL); $this->sql->insert('news', $news->getData()); $msg = new PSX_Data_Message('News record successful created', true); $this->setResponse($msg, null, 201); } else { throw new Exception('Missing field in record'); } } catch(Exception $e) { $code = $e->getCode() == 0 ? 500 : $e->getCode(); $msg = new PSX_Data_Message($e->getMessage(), false); $this->setResponse($msg, null, $code); } }
Here an example Oauth request to insert a news
Example 4.7. Sample POST request
POST /tests/psx/public/ HTTP/1.1 Host: 127.0.0.1 Accept: application/xml Content-type: application/xml Content-Length: 171 Authorization: OAuth realm="oat", oauth_signature="056413a4c2b9cb93bc2454902a2de25d549c219b%26eecde7a5f6e11556475c995252390b0160ba01e1", oauth_version="1.0", oauth_nonce="2ac118d94ca10fdfba2587b97a80dc89", oauth_signature_method="PLAINTEXT", oauth_consumer_key="64e197648df5f30acbc770d8a69d09bb391e78cb", oauth_token="901fbcf6e1f949f39c8458210f646c4407ec67f9", oauth_timestamp="1309609401" <?xml version="1.0" encoding="UTF-8"?> <news> <author>foobar</author> <title>And some great news</title> <body>And here the complete content ... hf ;D</body> </news>
Example 4.8. Sample POST response
HTTP/1.1 201 Created Date: Sat, 02 Jul 2011 12:23:21 GMT Server: Apache/2.2.12 (Win32) DAV/2 mod_ssl/2.2.12 OpenSSL/0.9.8k mod_autoindex_color PHP/5.3.0 mod_perl/2.0.4 Perl/v5.10.0 X-Powered-By: psx Expires: Thu, 09 Oct 1986 01:00:00 GMT Last-Modified: Thu, 09 Oct 1986 01:00:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Content-Length: 130 Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <message> <text>News record successful created</text> <success>true</success> </message>
This was an basic example howto protect your API with Oauth.
Note: This is an example implementation to show you the basic functionallity howto use the Oauth classes of PSX. Because of simplicity we use only a single consumer key and consumer secret normally you would save those in a table and gengerate per user a consumer key and secret. Please see the Amun project for a real implementation of the OAuth classes.
Table of Contents
To configure PSX you must make two steps first edit the configuration.php and second set the rights if you want use the caching mechanism.
To edit the configuration you must open the file configuration.php with an editor of your choice. The config is an php array with key value pairs. You must change the key "psx_url" so that its point to the psx public root. All other entries are optional. The following table describes each entry.
Key | Description |
---|---|
psx_version | The version of psx that you are using. |
psx_url | The absolute url to the psx folder |
psx_dispatch | Where we get the input path normally index.php/. |
psx_timezone | The default timezone |
psx_gzip | Whether to gzip the output of psx. The content gets only compressed if the browser support gzip. |
psx_debug | Whether psx runs in debug mode or not (display the trace if an exception is thrown). |
psx_module_default | The module wich is loaded by default |
psx_module_input | From wich source we get our input string |
psx_module_input_length | The max length of an input. If the request is longer the user gets an "414 Request-URI Too Long" response |
psx_sql_host | Your sql host. Only necessary if you need a sql connection |
psx_sql_user | Your sql user. Only necessary if you need a sql connection |
psx_sql_pw | Your sql pw. Only necessary if you need a sql connection |
psx_sql_db | Your sql db. Only necessary if you need a sql connection |
psx_cache_enabled | The general option whether caching is enabled or not |
psx_cache_expire | How long the cached result will remain in seconds |
psx_template_dir | This is the name of an folder in the dir template |
psx_template_default | By default you have to set in each module a template. Here you can set a default template wich is loaded if no template is specified. This must be a path to a template file in the template dir. |
psx_path_cache | The path to the cache folder |
psx_path_library | The path to the library folder. If this is null the classes are loaded from the include_path i.e. you can set this to null if you have installed the library via PEAR. |
psx_path_module | The path to the module folder |
psx_path_template | The path to the template folder |
By default PSX uses simple php as template engine because it is fast and you have more freedome to design a website. In your template you can access the variable (that you have assigned) with $[key]. You can also use some predefined variables wich are listed here:
Variable | Description |
---|---|
$config | The PSX_Config object wich holds the array from the configuration.php file. Note the object may contain sensitive informations like sql username and password. |
$self | This is the current URI. You can use this in a form to point to the module |
$url | The complete url including the dispath i.e. http://foobar.org/index.php/ |
$location | This is the path to your current template i.e. template/default in order to include other templates |
$render | The rendering time in seconds |
$base | The basepath wich can be used to include i.e. javascript, css or images. |
Because PSX is in an early stage the manual is not complete. I appreciate every help in making this documentation better. The documentation is writte in XML against the docbook specification. You can checkout the current version of this manual via SVN. The XML file is in doc/docbook/manual.xml. If you have made some changes that you want commit please contact me.
Further reading about PSX
Mailinglist: http://groups.google.com/group/phpsx
Examples: http://example.phpsx.org
Website: http://phpsx.org
Bugtracker: http://code.google.com/p/psx/issues/list
Repository: http://code.google.com/p/psx/source/checkout