Archive for the ‘LAMP’ category

How to use Google Charts API in your Secure, HTTPS webpage

November 9th, 2009

So you love Google Charts API and want to spice up your app with lots of pretty bar charts, Venn diagrams, Google-o-meters and 2D bar codes (QR Codes) – only problem is, you require that users connect to your site using a secure connection (https://yoursite.com/whatever). Well, as you are probably aware, the Google Charts API doesn’t ex

actly support SSL connections… directly.

Have no fear! If you are willing to give up a little bit of your own bandwidth, you can work around this problem. We are going to do this using a simple PHP script and if you want to get really fancy, Memcached to keep the redundant API calls to a minimum.

Let’s get started.
» Read more: How to use Google Charts API in your Secure, HTTPS webpage

Memory-tight, multi-threaded PHP Daemon

November 17th, 2008

Came across this nifty project on Google Code. It’s a multi-threaded, object-oriented PHP daemon which is very nicely written and easy to use.

http://code.google.com/p/phpmultithreadeddaemon/

Here’s their example of how to implement it. Everything needed to run the daemon is in the single included file “class.MTDaemon.php” – cool!


<?php

error_reporting(E_ALL);

require_once(include/class.MTDaemon.php);

class MTTest extends MTDaemon {

public function getNext($slot)
{
$this->lock();
$num = $this->getVar("num");
if ($num == null) $num = 1;
if ($num > 100) {
$this->unlock();
return null;
}
$this->unlock();

$rand = rand(0, 5);
echo "Next for slot " . $slot . " : " . $rand . "\n";
if ($rand == 0) return null;
else return $rand;
}

public function run($next, $slot)
{
$rand = rand(3, 10);
$this->lock();
$num = $this->getVar("num");
$this->setVar("num", $this->getVar("num") + 1);
$this->unlock();
echo "## Iteration #" . number_format($num) . " in " . $rand . "sec" . "\n";

sleep($rand);
return 0;
}

}

$mttest = new MTTest(2);
$mttest->handle();

?>

How to use PHP’s sprintf() on a MySQL query utilizing DATE_FORMAT()

August 2nd, 2008

It is good practice (common sense?) to filter your SQL queries.  One way to accomplish this in PHP is to utilize a function like sprintf() which will format a given string and integrate values into the string using conversion specifications which are passed in as arguments to the function.  In plain english, that means you can call the function, pass in a value and require that value to be a integer, for example.  If the value you passed in is a string, roughly speaking, it will sanitize your output.

An example in a MySQL query would be this.

<?php
// build our sql string.
$sql = "SELECT * FROM table WHERE field=%d";
$sqlf = sprintf( $sql, $somevalue );
$db->query($sqlf);
?>

As you can see, you can designate where the substitution will take place in the $sql string. That’s easy. But what happens if you need to use MySQL’s DATE_FORMAT() function? It requires that you pass in arguments to define its output (ie. Day as a word, day as a date, month as a number, etc).

<?php
// build our sql string.
$sql = "SELECT DATE_FORMAT( %b %M %d %Y, some_date_field ) as myDate FROM table WHERE field=%d";
$sqlf = sprintf( $sql, $somevalue );
$db->query($sqlf);
?>

This will fail. sprintf() will complain because you haven’t passed in enough arguments. It is expecting 5 values as part of the call, instead of just the one that you are trying to replace (in the SQL WHERE clause).

So what’s the solution? You have to “comment-out” the % that aren’t part of your sprintf() substitution. You can do this by putting another % in front of the ‘%’ symbols in the DATE_FORMAT() function. This deems them as a literal percent-sign instead of the start of another sprintf() “variable”.

<?php
// build our sql string.
$sql = "SELECT DATE_FORMAT( %%b %%M %%d %%Y, some_date_field ) as myDate FROM table WHERE field=%d";
$sqlf = sprintf( $sql, $somevalue );
$db->query($sqlf);

Hope that helps!

MySQL ON DUPLICATE KEY INSERT

December 18th, 2007

Have you ever wanted to write a single query that would update fields in a table – but you can’t be 100% sure the record exists yet for you to update? For example, you might have a table that holds configuration data for your application. There will be one record for each user in your system. You could use their “UserID” as the primary key (that is crucial to making this work).

Well, instead of doing this:

<?php
$sql = "SELECT COUNT(UserID) FROM configuration WHERE UserID='SomeUser'";
$result = mysqli_query($db,$sql);
if ($result && mysqli_num_rows($result)>0) {
$aResult = mysqli_fetch_array($result);
$iRecordExists = ($aResult[0]>0?1:0);
}

if ($iRecordExists>0) {
//do an update
$sql = "UPDATE configuration SET someField='someValue' WHERE UserID='SomeUser'";
mysqli_query($db,$sql);
}
else {
//do an insert
$sql = "INSERT INTO configuration SET someField='someValue', UserID='SomeUser'";
mysqli_query($db,$sql);
}
?>

You could just do this:


<?php
//insert the user's configuration field - if the record already exists - update instead
$sql = "INSERT INTO configuration SET UserID='SomeUser', someField='someValue' ON DUPLICATE KEY UPDATE someField='someValue' ";
mysqli_query($db,$sql);
?>

Simply put, the query will attempt to insert the configuration record first. If it finds that the specified UserID already has a configuration record in the table, it will simply update the existing record according to the values you include after “ON DUPLICATE KEY UPDATE”. You can include more than one field to update as well.

[Update: As Paul questioned in the comment below, the WHERE clause is not correct (in my original post). The trick is, you have to include the primary key as part of the insert statement - such as UserID in the example above.]

Trouble with PHP regular expression; REG_ERANGE error

November 29th, 2007

I had a situation where I needed to validate an email address that included an apostrophe. It is not widely known that the apostrophe (and a bunch of other symbols for that matter) are valid characters in the official RFC2822 specification for email address formats.

Anyway, I kept getting an error when I tried to add the apostrophe to my character classes in my regex. It gave me a strange error referencing REG_ERANGE. After some googling, I came across this blog post which led me to the answer. The problem is related to the placement of the dash (”-”) character in the regex.

Example 1:

if (ereg("[^a-zA-Z0-9_-.]", $userid)) {
    echo 'bad';
}
else {
    echo 'good';
}

The problem? The dash, or hyphen, being before the period. It thinks it’s a range, like you see in a-z. This may not be a bug, per se, but it’s certainly not smart enough for me.

The solution? Simply put the dash at the end of the regex.

Example 2:

if (ereg("[^a-zA-Z0-9_.-]", $userid)) {
    echo 'bad';
}
else {
    echo 'good';
}

MySQL Automated Backup and Testing Bash Script

October 31st, 2007

So – you can go to any one of 100,000 sites that will tell you how to do an automated MySQL database dump with some combination of mysqldump and crond, etc. But, I was recently faced with the question, “what happens if the dump file is corrupt? can we validate it before we pack it away with our backup service?” So I came up with this little shell script.

It does the following:

  1. Creates a backup of the selected db using mysqldump
  2. Generates an MD5 checksum of the backup file (written to a separate file)
  3. Attempts to restore the dumped file into a dummy test database
  4. If errors are encountered, it grabs the error and sends an email to the designated address
  5. If no errors are encountered, wraps the .sql and .sql.md5 in a timestamped, gzipped, tarball – then deletes the originals

Download the file here

#!/bin/sh
#######################################################
# LICENSE:
# (c) 2007 Brian Bell (GNU LGPL V2.1) You may
# view the full copyright text at:
# http://www.opensource.org/licenses/lgpl-license.html
#
# DESCRIPTION:
# A simple BASH script to do automate MySQL database
# backup; includes testing and MD5 hash creation.
# Emails designated address on failure.
#######################################################

## CONFIGURATION VARS
MYSQL_NAME=
MYSQL_HOST=
MYSQL_USER=
MYSQL_PASS=
MYSQL_TESTDB=
BACKUP_PATH=/path/to/backup/dir # No trailing slash
MAIL_SUBJECT=”TESTING MySQL Backup Error”
MAIL_TO=”monitor@yourdomain.com”

#######################################################
## We need to create a unique timestamp for use on the filename
TIMESTAMP=`date +%Y_%m_%d`

## Generate the base part of the filename to use in backing up
BACKUP_FILE_BASE=”${MYSQL_NAME}_${TIMESTAMP}”

echo “Backing up $MYSQL_NAME…”
/usr/bin/mysqldump –opt -c -e -Q -h $MYSQL_HOST -u $MYSQL_USER –password=$MYSQL_PASS \
–add-drop-table $MYSQL_NAME > $BACKUP_PATH/$BACKUP_FILE_BASE.sql

## MD5 the backup file
/usr/bin/md5sum -t $BACKUP_PATH/$BACKUP_FILE_BASE.sql > $BACKUP_PATH/$BACKUP_FILE_BASE.sql.md5

## Try to import the backup sql into a test db
MYSQL_RESULT=`/usr/bin/mysql -h ${MYSQL_HOST} -u ${MYSQL_USER} –password=${MYSQL_PASS} ${MYSQL_TESTDB} < \
${BACKUP_PATH}/${BACKUP_FILE_BASE}.sql >

${BACKUP_PATH}/mysql_test.log`

if [[ “$MYSQL_RESULT” =~ “ERROR” ]]
then
echo “The following error was encountered at `date` ” > ${BACKUP_PATH}/error_email.log
echo “” >> ${BACKUP_PATH}/error_email.log
echo “#####################################################################” >> ${BACKUP_PATH}/error_email.log
echo $MYSQL_RESULT >> ${BACKUP_PATH}/error_email.log

echo “SENDING ERROR EMAIL TO: ${MAIL_TO}”
/bin/mail -s “$MAIL_SUBJECT” “$MAIL_TO” < ${BACKUP_PATH}/error_email.log
else
tar czpf $BACKUP_PATH/$TIMESTAMP_$BACKUP_FILE_BASE.sql.tar.gz $BACKUP_PATH/$BACKUP_FILE_BASE.sql* –remove-files
fi