xajax – PHP Notices/Warnings

Today we were playing with xajax trying to eliminate some redundant page reloads and also keeps some divs hidden based on user input without having to manage their state.  All was working as expected on our Linux box (Fedora) but when we tried to get it running on IIS it was dying.  It looked like no response or anything was coming back from some simple AJAX calls.  So we did as every good web developer should do – bust out FireBug.  Looking at the NET results we noticed we were in fact getting a response from our request but with an additional “PHP Notice undeclared variable message” (not show in the pic). It didn’t really dawn on us that this was the culprit until we opened IE 7 and it returned with a dialog box saying it could not parse the XML because of a space, pointing out the “Notice” message was returned before the XML response.  A closer look at our PHP.ini file resulted in use turning off Notices and turning on Errors only.  This was the issue.  Goes to show you having two browsers for debugging is a good thing :)

image

Read More

Subdomain Cookies and Localhost

So I have a site – we’ll call www.site1.com that sets a client side cookie named CookieName1 and I need a subdomain test.site1.com to be able to read that value. Using php’s standard setcookie() method I set the cookie on www by using:

setcookie( “CookieName1″, $CookieName1Value, $CookieExpDate, “/”, “.site1.com” );

This works, no problem.  Now test.site1.com uses .NET to read in the value and do something.  Pretty standard stuff here:

  If Request.Cookies(“CookieName1″) IsNot Nothing Then

   ”DO SOMETHING

  End If

 

Build > Debug, set a breakpoint on the if block, skips right over it.  Huh?  I make sure IE has the cookie, try again.  Nope, Request.Cookies(“CookieName1″) is Nothing.  Can’t be an IE thing can it?  Run same scenerio in FireFox – same result.  Then it dawns on me, I’m not running this under test.site1.com, I’m running this under localhost.  Everything was working as expected, cookies can only be read by *.site1.com.  So how am I going to test this thing on my local machine? I do have a sandbox, test1sandbox.site1.com, but what if I didn’t?  A simple solution is to change the host file found at %SystemRoot%\system32\drivers\etc\ with:

127.0.0.1 localhost
127.0.0.1 test1.site1.com

Run another Debug, change the http://localhost to http://test1.site1.com and now I’m able to read cookies from *.site1.com. Nifty.

Read More

How to Expire a Cookie at Midnight using PHP

One line of code:

setcookie(“CookieName”, “CookieValue”, mktime(23, 59, 59, date(“m”), date(“d”), date(“y”)));

Read More

Upload Files to MySQL using PHP Tutorial

I much prefer to upload files to mysql instead of saving them directly to the file system. I can run database backups/mirrors that are much easier to manage then if files were placed on the file system.

Here are the simple scripts I use to upload files and a script to stream the file back to the browser.

MySQL Database Script:

CREATE TABLE `UploadedFiles` (
`UploadedFileID` int(11) NOT NULL auto_increment,
`name` varchar(30) default NULL,
`type` varchar(30) default NULL,
`size` int(11) default NULL,
`content` longblob,
PRIMARY KEY (`UploadedFileID`)
) TYPE=MyISAM;


Upload Script:

'holds db constructor
include("{$_SERVER['DOCUMENT_ROOT']}/phplibrary/dbconnect.php");
###################
//Consume Post Vars
###################
if (!empty($_POST['upload']))
{
//Loop thru Post Array
foreach($_POST as $key => $value) {
$$key = $value;
}

$connect->connect_db(mydatabase)

//Insert File
if(isset($_POST['upload']) && $_FILES['SpecialFile']['size'] > 0) {
$fileName = $_FILES['SpecialFile']['name'];
$tmpName = $_FILES['SpecialFile']['tmp_name'];
$fileSize = $_FILES['SpecialFile']['size'];
$fileType = $_FILES['SpecialFile']['type'];
$fp= fopen($tmpName, ‘r’);
$content = addslashes($content);
fclose($fp);
}
if(!get_magic_quotes_gpc()) {
$fileName = addslashes($fileName);
}

$query = “INSERT INTO UploadedFiles (name, size, type, content) “.
“VALUES (‘$fileName’, ‘$fileSize’, ‘$fileType’, ‘$content’)”;

$result = mysql_query($query);
if (!$result) {
dberror (mysql_error(), $_SERVER['PHP_SELF'] );
echo mysql_error();
}

//Display Confirmation
$message = urlencode(“Your file has been uploaded.”);
header( “Location: confirmed.php?m=$message” );
exit;
}
?>


Upload File:

To download the file I prefer to push the file down as octet stream/binary data (NOTE: To display images you would need to push out the particular mime type). That way users get the “Save” dialoge instead of the browser (especially IE) automatically trying to open with what it *thinks* should. The following codes displays the file in a drop down list for users to select and have the file streamed to their web browser.

Download File Script

//holds db constructor
include("{$_SERVER['DOCUMENT_ROOT']}/phplibrary/dbconnect.php");

if (!empty($_POST['GetFile']))
{
$UploadedFileID = $_POST["UploadedFileID"];
$connect->connect_db(mydatabase)
$query = “SELECT * FROM UploadedFile WHERE UploadedFileID = $UploadedFileID”;
$result = mysql_query( $query );
if( !$result ) {
echo mysql_error();
exit;
}

$row = mysql_fetch_array( $result );
if (!empty($row["content"]))
{
// Output the MIME header – Force as Octet Stream
// You could get this from the FileType Column
header(“Content-type: application/octet-stream”);
header(“Content-Length: ” . strlen($row['content']) );
header(“Content-Type: application/octet-stream”);
header(‘Content-Disposition: attachment; filename=”‘.$row['name'].’”‘);
header(“Content-Transfer-Encoding: binary\n”);
echo $row['content'];
}

}
?>


$connect->connect_db(mydatabase)
$result = mysql_query(“SELECT UploadedFileID, name FROM UploadedFiles”);
if ($myrow = mysql_fetch_array($result)) {
do { ?>

Read More

RSS Feed any MySQL Database using PHP

To some folks rss is this hot new technology that is changing our lives in technology. The truth is rss is a specific formated text file that people finally have standarized on. It’s the standarization that changes people lives, not neccessary the technology. Anyway, a while back I wanted to rss feed our knowledgebase. The knowledgebase articles are stored in a mysql database. I played around with using PEAR::PACKAGE::XML to do the job but found it to be a bit overkill. So I wrote my own xml builder – source code is below or you can download the php rss feed mysql database code. What is nice, is that you can RSS feed any database.

// prepare HTML text for use as UTF-8 character data in XML
function cleanText($intext) {
return utf8_encode(
htmlspecialchars(
stripslashes($intext)));
}

// set the file's content type and character set
// this must be called before any output
header("Content-Type: text/xml;charset=utf-8");

// retrieve database records

$db = mysql_connect("YourMySQLSERVER", "YOURUSERNAME", "YOURPASSWORD");
if (!$db)
{
error_log("Error: Could not connect to database in rss.php.");
exit;
}

// store items from the database in the $result1 array
mysql_select_db("knowledgebase");

$query1 = "SELECT faqarticles.question, faqarticles.content, SUBSTRING(content,1,600) as mycontent,
faqarticles.cat, faqarticles.id, faqarticles.date FROM faqarticles WHERE
faqarticles.approved != '1'
ORDER BY faqarticles.date DESC";
$result1 = mysql_query($query1);
$phpversion = phpversion();

// display RSS 2.0 channel information

ECHO <<

http://www.yourlinkgoeshere.com Describe your RSS Feed Heredescription>
en-us
http://backend.userland.com/rss
PHP/$phpversion


http://www.yoursite.com/images/YourLogo.gif

http://www.yoursite.com/index.php 140
60
Describe Your Image

END;

// loop through the array pulling database fields for each item
for ($i = 0; $i < mysql_num_rows($result1); $i++) {
@$row = mysql_fetch_array($result1);
$title = cleanText($row["question"]);
$link = "http://www.YourSite.com/kb/index.php?article=".$row["id"];
$description = $row["mycontent"];

//Replace Ugly HTML that got into the Knowledgebase with nothing
$desc_replace = array("

 

“, “

 

“, );
$desc_replace_with = array(“”, “”, “”);
$desc_temp = str_replace($desc_replace, $desc_replace_with, $description);

//Now clean the HTML
$mydescription = cleanText($desc_temp);
$pubDate = $row["date"];

// display an item
ECHO <<

$link $mydescription… For the entire article, please visit our site.

$pubDate


END;

}

ECHO <<



END;

?>

Read More

Performance Testing with PHP

After writing some functions or classes its good idea to make sure your code is executing in a timely fashion, especially for web applications. For PHP I use a function derived from the chronmeter class to look for bottle necks (the function is below or download it here).

We recently ran into a problem of a web form running particular slow. It had the following functionality.

  • Insert some data into 2 mysql tables
  • Grab some data from a Microsoft SQL Database
  • Read in a text file, replace some verbiage, then send out a couple of emails.
  • I architected the form and was letting one of our interns implement it. Everything seemed pretty straight forward – this code should fly. After the site went live, I checked out the form and found it running slow. Using the chronometer function I paired it down to our phpmailer. Turns out we were using php’s built in mail function and not phpmailer.

    After switching to phpmailer and setting the option to smtp, I cut the runtime in half. I then realized we were sending out 2 emails and each time opening/closing an smtp connection. I refactored so only 1 connection was opened. Here are the results of the average form runtime:

  • PHP’s built in mail function: Avg: 3 seconds.
  • PHPMAILER function with 2 connections: 1.5 seconds.
  • PHPMAILER function with 1 connection: .105 seconds
  • To use the chronometer function, simply call it before a class or function call and then call it right after it .

    $chronometer(); //start
    $this->SendSalesEmail($_POST);
    $runtime = chronometer();
    print “SendSalesEmail took: $runtime”;

    $CHRONO_STARTTIME = 0;

    define(”RET_TIME”, “s”); //Can be set to “ms” for milliseconds or “s” for seconds
    function chronometer()
    {
    global $CHRONO_STARTTIME;

    $now = microtime(TRUE); // float, in _seconds_

    if (RET_TIME === ’s’) {
    $now = $now + time();
    $malt = 1;
    $round = 7;
    } elseif (RET_TIME === ‘ms’) {
    $malt = 1000;
    $round = 3;
    } else {
    die(”Unsupported RET_TIME value”);
    }

    if ($CHRONO_STARTTIME > 0) {
    /* Stop the chronometer : return the amount of time since it was started,
    in ms with a precision of 3 decimal places, and reset the start time.
    We could factor the multiplication by 1000 (which converts seconds
    into milliseconds) to save memory, but considering that floats can
    reach e+308 but only carry 14 decimals, this is certainly more precise */

    $retElapsed = round($now * $malt - $CHRONO_STARTTIME * $malt, $round);

    $CHRONO_STARTTIME = $now;

    return $retElapsed;
    } else {
    // Start the chronometer : save the starting time

    $CHRONO_STARTTIME = $now;

    return 0;
    }
    }

    ?>php_chronometer.txt

    Read More