Archive

Archive for the ‘PHP’ Category

Strings and Singletons in PHP

March 24th, 2009

Hi all haven’t posted in a while.

Been doing a fair bit of PHP recently and have come across some useful PHP snippets.

I was looking to perform multiple MySQL queries but the plain old mysql_query doesn’t allow it unfortunately. After doing a little bit of digging around I found that you need to use mysqli_multi_query to perform multi-queries. Of course you need to connect to your MySQL database using mysqli_connect(and I believe you need to have enabled a seperate mysqli module for php).

I’ve also been doing quite a bit of string manipulation with php. I was looking for a similar function to Coldfusion’s ListContainsNoCase whereby I needed to search a comma seperated list for a specific value. Didn’t find anything especially useful so learnt that using the explode function converts a string separated by a specified delimiter into an array which can then be searched using the in_array function. The strict flag is especially useful if you require an element of the array to match exactly the original term you’re looking for in the list.

String comparison was another sticking point last week. I had a string containing a single character, “*” and attempted compare this string variable using the double equality operator(i.e. $myVar == “*”) but was getting a false match every time. After printing out the variable many times and ensuring that it did indeed have the right value I began to think something else was wrong and had a look at the php documentation. After trying out the Strcasecmp function I began getting the matches I expected. strcasecmp is a binary safe case-insensitive string comparison. A binary-safe function is essentially one that treats its input as a raw stream of data without any specific format. It should thus work with all 256 possible values that a character can take (assuming 8-bit characters). Most functions are not binary safe when using any special or markup characters, such as escape codes or those that expect null-terminated strings. A possible exception would be a function whose explicit purpose is to search for a certain character in a binary string.(thank you Wikipedia). As I was working with a special character my string comparison was crapping out, now I know why.

Creating a singleton class in PHP is something that is a very common operation and after looking at a handy tutorial I came up with a handy singleton class which is used to obtain and instantiate singleton objects. Further work needs to be done on this to allow for multiple objects to be instantiated but it works pretty well for me.(sorry about the indentation, Wordpress screwed it up on pasting it in)

[code lang="php"]

class Singleton
// ensure that only a single instance exists for each class.
{
function getDBConnection()
{ static $db = null;
global $dbLocation;
global $dbusername;
global $dbpassword;
global $cstdatabase;

if($db == null)
{ $db = mysql_connect($dbLocation,$dbusername,$dbpassword);
mysql_select_db($cstdatabase) or die( "Unable to select database");
}

return $db;

}

//TODO: Make this more flexible for parameters into inited functions, possibly an array
public function &getInstance ($class, $classPath=null,$arg1=null)
// implements the 'singleton' design pattern.
{ $lowerClassName = strtolower($class);
static $instances = array(); // array of instance names

if (array_key_exists($lowerClassName, $instances)) {
// instance exists in array, so use it
$instance =& $instances[$lowerClassName];

} else {
// load the class file (if not already loaded)
if (!class_exists($lowerClassName)) {
if($classPath)
{
require_once "$classPath/$class".".php";
}
else
{
switch ($lowerClassName) {
case 'object1':
require_once 'object1/Object1.php';
break;

case 'object2':
require_once 'object2/Object2.php';
break;
default:
require_once "$class".".php";
break;
} // switch
}

} // if

// instance does not exist, so create it
$newClass = new $class();

$instances[$lowerClassName] = $newClass;

if(method_exists($newClass,"init"))
{ if($arg1 != null)
{ $newClass->init($arg1);
}
else
{
$newClass->init();
}
}

$instance =& $newClass;
} // if

return $instance;

} // getInstance

} // singleton

?>
[/code]

edlong Archive Post, PHP

Setting up Apache, PHP 5 and MySQL on Leopard

March 24th, 2009

Going to be a short blog post as Leopard has made this process very simple as PHP5 has been included as standard with the new OSX.

First thing you need to do is open terminal and edit your http.conf file by typing:

nano -sw /etc/apache2/httpd.conf

Firstly you need to enable the php module. Search for ‘php5_mod’ by typing it in when you press ctrl+w and press enter. This will bring you to a line with a hash before it….

#LoadModule php5_module libexec/apache2/libphp5.so

Remove this hash to enable php5.

Next you need to setup your document root, i.e. the location your webserver will default to when you go to http://localhost. Search for ‘DocumentRoot’ within nano again by pressing Ctrl+w and hitting return. Alter the location (I think its Library/WebServer or something by default) to be whatever you wish your webserver root to be. I set it to be the Sites folder of the User I setup for Leopard.

Next you need to enable Apache, this is exceedingly easy. Go to System Preferences and then Sharing. Click the checkbox next to Web Sharing and apache should be ready to do. Put a sample html or php file(including is always a good way to test if php is working) in the document root and go to http://localhost and you should see the sample page.

Next you need to get MySQL. I got it here: http://mirrors.sunsite.dk/mysql/downloads/mysql/5.0.html#macosx-dmg.
Follow the very easy steps in the package and you should be hunky-dorey!

edlong Archive Post, MySQL, PHP

PHP named locks, redirecting & logging

March 24th, 2009

Hi all haven’t posted in a while have a couple of posts to catch up on :)

I’ve recently have the need to perform locking in php on the server level. Basically I want just a single php script to execute a piece of code at any time. This requirement was brought about by race conditions whereby two php scripts would go and execute the same piece of code which would consequently conflict with one another. I needed to stop this. The solution is nice and easy and works a treat.

Whenever a php script comes in and requests a lock on a piece of code it attempts to create a directory using phps mkdir with a specific name myLock1. If the directory already exists then the mkdir returns false and the locking fails. If the mkdir completes then the php script has locked the section of code. Now when another seperate php script comes in and tries to create the directory mkdir will return false and the locking will fail.

When the php script is finished with a piece of code then it unlocks by deleting the directory using rmdir. Now a new php script is free to come in lock the piece of code again.

This locking works across all php scripts (i.e. is server wide) and provides named locks as you can give the directories different names. So one section of code may be locking a myLock1 directory and another part be locking myLock2 directory but these won’t interfere with one another. I’ve attached the code for this simple locking below and highlighed how it would be used to lock a piece of code.

[code lang="php"]
class FLock
{ private $files = array();
private $oUUID = "";

function __construct()
{ $this->oUUID = new UUID();
}

function __destruct()
{ foreach($this->files as $file)
{
fclose($this->files['$file']);
}
}

private function saveFileHandle($filepath)
{
if(!array_key_exists("$filepath",$this->files))
{
$this->files["$filepath"] = array();
$this->files["$filepath"]['directory'] = $filepath;
$this->files["$filepath"]['locked'] = false;

}

}

public function attemptFileLock($filepath=false, $lockFile=true)
{
global $fileLockingLocation;

$this->saveFileHandle($filepath);

$canLock = false;

if($lockFile == true)
{ if(!$this->files["$filepath"]['locked'])
{ try
{
$canLock = mkdir("$filepath");
if($canLock)
{
$this->files["$filepath"]['locked'] = true;

}

}
catch(Exception $ex)
{
LogError($ex);
}
}
}
else
{ if($this->files["$filepath"]['locked'])
{
rmDir("$filepath");

$this->files["$filepath"]['locked'] = false;

//TODO - Fix
return true;

}
}

return $canLock;
}

public function removeAllFileLocks()
{ foreach($this->files as $file)
{ rmDir($file['directory']);
$this->files[$file['directory']]['locked'] = false;
}
}
}
[/code]

To lock the some code you need to just do like what I’ve done below.

[code lang="php"]
$this->oFL = new fLock();
$fileLockResult = $this->oFL->attemptFileLock("/fileLocks/".$lockName."_lock",true);
if($fileLockResult)
{
//Perform mySQL inserts,deletes etc.
$fileLockResult = $this->oFL->attemptFileLock("/fileLocks/".$lockName."_lock",false);
}
else
{
//Sleep between 0.5 - 1 second
usleep(500000+(mt_rand(1,10))*500000);
}
[/code]

I’ve had to perform php redirects of late also, its nice and easy but as Michael found out, even when you put a redirect in a chunk of code, the rest of the script gets parsed and the redirection doesn’t occur straight away. So you may want to put in a die() or something after the redirect if you wish to abort the rest of the page’s processing.

header( ‘Location: http://www.yoursite.com/new_page.html’ ) ;

Performing error logging with PHP is another task I’ve wanted to do of late. Basically I’ve created a php wrapper page that takes in a script location from the Asterisk dial plan and executes the passed in script within a try catch block. Wrapping the script execution within the try provides a simple error logging mechanism. Anywhere I want to log errors that are fatal to the application I can just perform a throw within a php script and the top-most wrapper will always catch and log the error.

[code lang="php"]
#!/usr/bin/php -q

require_once $phpScriptPath.'common/phpagi.php';
require_once ("utility/logging.php");

global $agi;
try
{ if(!isset($agi))
{ $agi = new AGI();
}
$scriptName = $agi->get_variable("scriptName");
$agi->exec("AGI",$scriptName['data']);

}
catch(Exception $ex)
{ if(!isset($agi))
{ $agi = new AGI();
}

$errorFileName = 'error-'."date-".date("dmy_His");
$errorInfo = "Error message: ".$ex->getMessage();
$errorCode = "Error code: ".$ex->getCode();
$errorFile = "File: ".$ex->getFile();
$errorLineNo = "Line number: ".$ex->getLine();

if(!isset($agi))
{
$errorCode = $errorCode." - AGI cannot be created.";
$errorFile = $errorFile." - applicationWrapper.php catch block.";
}

//Log to error log directory
writeVariableToFile($errorInfo,$errorFileName);
writeVariableToFile($errorCode,$errorFileName,true);
writeVariableToFile($errorFile,$errorFileName,true);
writeVariableToFile($errorLineNo,$errorFileName,true);

if(isset($agi))
{ //Log to terminal if possible
$agi->verbose($errorInfo);
$agi->verbose($errorCode);
$agi->verbose($errorFile);
$agi->verbose($errorLineNo);
$agi->text2wav($ex->getMessage());
}

//Log to php error log
error_log($errorInfo);
error_log($errorCode);
error_log($errorFile);
error_log($errorLineNo);

exit(0);

}

exit(0);

?>
[/code]

The error_log is a built in php error logging system. You can specify where PHP logs errors to within you php.ini config file, I set it up to log to the system log by uncommenting the error_log = syslog line but you can easily setup your own location for logging errors.

From the Asterisk dial plan i.e. the extensions.conf you basically have something like

exten => s,n,Set(scriptName=/my/Path/To/File/myfile.php)
exten => s,n,AGI(/path/to/wrapper/applicationWrapper.php)
exten => s,n,Hangup()

edlong Archive Post, Asterisk, PHP

Get a CFC name, simultaneous instances of FF(again), XMLSearch case-sensitivity and Asterisk stats

March 24th, 2009

Hi all,

Today I finally sorted out getting multiple instances of Firefox running on my Mac simultaneously after having profile problems for the last few weeks with the new FF version. I followed the steps in the links below to get it working on Leopard, so I’m running Firefox 2.0.11 and Firefox 3 Beta 3. I like the beta a lot, much more stable than the older version, I would like to turn off the hinting in the URL as it occasionally promotes certain visited sites over others when I don’t want it to based on name(ie. I might want to go to webmail.edmundlong.com and when I type in ‘webmail’ into the URL it may suggest another site e.g. www.abertay.ac.uk/webmail over it when I don’t want it to because I’ve visited it more often)

http://support.mozilla.com/kb/Running+different+versions+of+Firefox+at+the+same+time

http://www.jeroencoumans.nl/journal/multiple-firefox-versions

Here’s a small ColdFusion snippet to get the name of a cfc using the metadata. cfcname contains the name of the cfc.

[code lang="xml"]




[/code]

I’ve been working on coming up with a way of accessing the Asterisk CLI from a php page so that stats could be delivered to a webpage. After looking around a bit I see that there is an Asterisk Manager facility that can execute some Asterisk commands along with CLI actions. Below is the code I’m currently using where I have a text-box that I can enter some CLI command e.g. sip show peers and the result is displayed on screen. I’m planning on maybe doing something like this to display some backend stats from the Asterisk system, I could get conference information, number of connected IAX & SIP peers and a whole bunch of other stats. Asterisk doesn’t return the data in a very friendly format though but more on that when I get into it a bit more.

[code lang="php"]

function executeAction($server,$username,$secret,$port,$action,$variable='')
{
$socket = fsockopen($server,$port, $errno, $errstr, 1);
fputs($socket, "Action: Login\r\n");
fputs($socket, "UserName: $username\r\n");
fputs($socket, "Secret: $secret\r\n\r\n");
fputs($socket, "Action: Command\r\nCommand: $action\r\n\r\n");
/*fputs($socket, "Action: $action\r\n\r\n");
if($variable != '')
{ fputs($socket, "Peer: $variable\r\n\r\n");
}*/
fputs($socket, "Action: Logoff\r\n\r\n");
$count=0;$array;
while (!feof($socket)) {
$wrets = fgets($socket, 8192);
$token = strtok($wrets,':(');
$j=0;
while($token!=false & $count>=5)
{
$array[$count][$j]=$token;
$j++; $token = strtok(':(');
}
$count++;
$wrets .= '
';
}

for($i=5;$i<$count-4;$i++){ echo '

'.$array[$i][0].'

'.'

'.$array[$i][1].'

'; }

fclose($socket);
}

function createActionList($server,$username,$secret,$port,$action="ListCommands")
{
$socket = fsockopen($server,$port, $errno, $errstr, 1);
fputs($socket, "Action: Login\r\n");
fputs($socket, "UserName: $username\r\n");
fputs($socket, "Secret: $secret\r\n\r\n");
fputs($socket, "Action: ListCommands\r\n\r\n");
fputs($socket, "Action: Logoff\r\n\r\n");
$count=0;$array;
while (!feof($socket)) {
$wrets = fgets($socket, 8192);
$token = strtok($wrets,':(');
$j=0;
while($token!=false & $count>=5)
{
$array[$count][$j]=$token;
$j++; $token = strtok(':(');
}
$count++;
$wrets .= '
';
}
echo "

";
/*echo 'Command :

';*/
echo "

Command :

";
echo "

Parameter :

";

echo "
";

echo "

";
fclose($socket);
}

if ($_POST['submit'])
{ executeAction('127.0.0.1','asterisk','asterisk',5038,$_POST['managersAction'],$_POST['variable']);
}
else
{ createActionList('127.0.0.1','asterisk','asterisk',5038);
}

?>

[/code]

This code is very very insecure and I’m using it only for testing, anyone could type ‘restart now’ to reboot your asterisk system!

I had a couple of problems when using XML search because XMLSearch in ColdFusion is case-sensitive. I had an XML document like the one below

[code lang="xml"]

<[CDATA[abc]]>

[/code]

I used the xpath expression /config/edstest to search for the ‘edsTest’ node but of course this failed due the case-sensitivity involved. The solution was to take the XML and change it all to upper case using UCASE(xml). The good thing is that ColdFusion ignored the content between the CDATA tags and so didn’t resize ‘abc’ which is exactly what I wanted. I then just changed my xpath to /CONFIG/EDSTEST and the search performed as expected.

edlong Archive Post, ColdFusion, PHP, XML

Reading RSS Feeds in php and Javascript table sorting

March 24th, 2009

Hello there,

Been working with SimplePie recently, its an RSS feed reader/parser that works with PHP. So far the results have been really good, it takes only 4 lines to go and fetch an RSS and return it in a friendly format:

[code lang="php"]
$feed = new SimplePie();
$feed->set_cache_duration($cache_time);
$feed->set_feed_url($URL);
$feed->init();
[/code]

I’ve not seen where the cache is sent yet OR what it actually caches but seems pretty easy.

I started using the JQuery tableSorter utility yesterday also. It is good enough, not as good as I’d like though. I had to manually resize some of the images that are used within the tags as they were leaving too much space which caused the headings to move onto a third line. Also I don’t know if they can use filters yet or if its possible to run ajax on the table. Anyway though getting the table sorter working is pretty straight forward

Get the full release from http://tablesorter.com and place jquery-latest.js, jquery.tablesorter.js in somewhere that can be read by your page(I’m using ColdFusion). Place the following code in your header:

[code lang="xml"]




[/code]

Once done I just made my table:

[code lang="xml"]

DATA STUFF
Header 1 Header 2


[/code]

That worked for me anyways!

Apart from that I’ve gone back onto using Asterisk recently again and will be doing a bit more PHP AGI in the near future so expect to hear some more about that!

edlong Javascript, PHP

PHP AGI Hangup

March 24th, 2009

Hi all,

Hangups are handled by PHP AGI by registering a sig_handler function. Whenever a user hangs up then this function is called. However as I found out recently you cannot use the agi within the hangup handler. You can use the verbose command and see what it outputs to the system/error log as the verbose command outputs to the default php error log as well as to the Asterisk CLI. Here is some simple code to register your hangup handler:

function sig_handler($signo)
{	//Do some stuff in here
	exit(0);
}

//Register the hangup handler
if (function_exists('pcntl_signal'))
{
      pcntl_signal(SIGHUP,  "sig_handler");
}

I’ve no idea what pcntl_signal is but its installed alongside Asterisk by default I believe so you shouldn’t need to do anything extra to get it working.

If you are stuck, the approach we took is to set some variables in the dialplan and have some conditional statements within the dialplan to check these variables. There is a special extension ‘h’ which is called when a hangup occurs. The conditional Gotoif checks for a boolean statement which if true will attempt to go to the first extension, if false it will go to the second extension.

exten => h,1,GotoIf($[${EXISTS(${aVar})}]?2:4)
exten => h,2,DoSomething()
exten => h,3,GotoIf(${aVar} > 0 ? 4:5)
exten => h,4,Goto(some_extension)
exten => h,5,Goto(some_extension)

PS. I’ve noted that labels don’t appear to be working(for me at least) in the dialplan. By labels I mean:

exten => h(myLabel),2,DoSomething()

According to the docs I should be able either of below within a GotoIf:

exten => h,1,GotoIf($[${EXISTS(${aVar})}]?myLabel:4)
exten => h,1,GotoIf($[${EXISTS(${aVar})}]?2(myLabel):4)

Both of these fail for me, telling me that the extension doesn’t exist.

edlong Archive Post, Asterisk, PHP, PHP AGI