<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Plant Wars &#187; Programming</title>
	<atom:link href="http://blog.plantwars.com/index.php/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.plantwars.com</link>
	<description>Development of a PBBG</description>
	<lastBuildDate>Wed, 10 Mar 2010 01:23:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>MySQL Date Functions and Determining if a User is Active</title>
		<link>http://blog.plantwars.com/index.php/2009/03/01/mysql-date-functions-and-determining-if-a-user-is-active</link>
		<comments>http://blog.plantwars.com/index.php/2009/03/01/mysql-date-functions-and-determining-if-a-user-is-active#comments</comments>
		<pubDate>Mon, 02 Mar 2009 04:24:11 +0000</pubDate>
		<dc:creator>jon</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://blog.plantwars.com/?p=20</guid>
		<description><![CDATA[I learn something every time I look at the MySQL Reference Manual: Date and Time Functions.  I should really look at it more often. Too often &#8211; always &#8211; I do not have enough time to spend time adding new features to Plant Wars.  Between having a full time day job and a baby at [...]]]></description>
			<content:encoded><![CDATA[<p>I learn something every time I look at the <a href="http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html">MySQL Reference Manual: Date and Time Functions</a>.  I should really look at it more often.</p>
<p>Too often &#8211; always &#8211; I do not have enough time to spend time adding new features to <a href="http://www.plantwars.com">Plant Wars</a>.  Between having a full time day job and a baby at home, I&#8217;m a little pressed for time. That means that as soon as I come up with a way to do something, I hit the ground running. This means I typically end up with very sub-optimal solutions.</p>
<p>As a rather embarrassing example, consult the following code snippet I was using to determine if a user had been active in the past 10 minutes. Any time a user is active, the LastActive attribute in the Users table is updated. Here, this value has been stored in the $lastActive variable.</p>
<pre><code class="php">
$lastActive = explode(" ", $lastActive);
$date = explode("-", $lastActive[0]);
$time = explode(":", $lastActive[1]);
$online = false;
if (date("d") == $date[2] &amp;&amp; date("m") == $date[1] &amp;&amp; date("Y") == $date[0]) { // user was active today
   if (date("H") == $time[0] &amp;&amp; date("i") &lt;= $time[1]+10) { // user was active in last 10 minutes - MODIFY TO CHECK IF USER WAS ACTIVE IN LAST 10 MINUTES EVEN THOUGH IT WAS THE PREVIOUS HOUR OF THE DAY
      $online = true;
   }
}
</code></pre>
<p>As you can see, even doing it in this ridiculously drawn out way, it still would mess up if, for example, a user had been inactive at 4:59 and it is now 5:01.</p>
<p>After consulting the MySQL date functions again, I have come up with a much more eloquent (and sensible) solution:</p>
<pre><code class="php">
	$query = "SELECT *, NOW()&lt;DATE_ADD(LastActive, INTERVAL 10 MINUTE) AS Active FROM Users WHERE Id='".$id."'";
	$result = mysql_query($query);
	$row = mysql_fetch_assoc($result);
</code></pre>
<p>Now to test if a user has been active in the past 10 minutes, I just check if ($row["Active"]).</p>
<p>To explain, <strong>NOW()</strong> returns the current date and time. <strong>DATE_ADD(<em>date</em>, INTERVAL <em>expression unit</em>)</strong> adds the specified amount to the date. Don&#8217;t use plural units (MINUTE is correct, MINUTES is not).</p>
<p>To summarize, it is best to do your research into the capabilities your available tools, as it will often save you time, make your application faster, your code more readable, and just generally be a better solution.</p>
<p><strong>Update 3/3/2009</strong></p>
<p>As <a href="http://www.reddit.com/r/programming/comments/81brc/how_not_to_compare_dates_with_phpmysql/c07zcii" target="_blank">wwosik pointed out on reddit</a>, this is an acceptable solution for determining if a single user has been active in the past 10 minutes. But what if you want to find all active users? It is costly to have MySQL execute the date functions for every row when it is unnecessary.</p>
<p>To solve this problem, we need to calculate the date/time 10 minutes in the past and then we can just store this value and compare the LastActive attribute of each row to it, without needing to calculate it for every user.</p>
<p>To do this, I use the <a href="http://us.php.net/mktime" target="_blank">mktime()</a> and <a href="http://us.php.net/date" target="_blank">date()</a> functions.</p>
<pre><code class="php">
// <span class="type">int</span> <span class="methodname"><strong>mktime</strong></span> ([ <span class="methodparam"><span class="type">int</span> <tt class="parameter">$hour</tt><span class="initializer">= date("H")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$minute</tt><span class="initializer">= date("i")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$second</tt><span class="initializer">= date("s")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$month</tt><span class="initializer">= date("n")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$day</tt><span class="initializer">= date("j")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$year</tt><span class="initializer">= date("Y")</span></span> [, <span class="methodparam"><span class="type">int</span> <tt class="parameter">$is_dst</tt><span class="initializer">= -1</span></span> ]]]]]]] )
$activeThresholdUnix = mktime(date("H"), date("i")-10, date("s"), date("m"), date("d"), date("Y"));
// Since mktime returns the Unix timestamp, we need to convert it into something comparable with the SQL timestamp
$activeThreshold = date("Y-m-d H:i:s", $activeThresholdUnix);
$query = "SELECT Id, Name, Level FROM Users WHERE LastActive&gt;'".$activeThreshold."' ORDER BY Level DESC";</code></pre>
<p>There is probably a better way to calculate the time 10 minutes ago, but this is certainly a step in the right direction; it is much more efficient than performing unnecessary calculations for every row.</p>
<div style="float: left; width: 140px; height: 21px; overflow: hidden; position: relative; left: 8px;"><script>//<![CDATA[
reddit_url="http://blog.plantwars.com/index.php/2009/03/01/mysql-date-functions-and-determining-if-a-user-is-active";
//]]&gt;
</script><script language="javascript" src="http://reddit.com/button.js?t=1"></script></div>]]></content:encoded>
			<wfw:commentRss>http://blog.plantwars.com/index.php/2009/03/01/mysql-date-functions-and-determining-if-a-user-is-active/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dynamically Generated Graphs With PHP</title>
		<link>http://blog.plantwars.com/index.php/2009/02/28/dynamically-generated-graphs-with-php</link>
		<comments>http://blog.plantwars.com/index.php/2009/02/28/dynamically-generated-graphs-with-php#comments</comments>
		<pubDate>Sun, 01 Mar 2009 02:55:29 +0000</pubDate>
		<dc:creator>jon</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[graph]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.plantwars.com/?p=8</guid>
		<description><![CDATA[A requested feature I recently implemented was the ability to view your character&#8217;s progress in a chart. For example, you can view how quickly you&#8217;ve leveled for the past month, or see the fluctuations in the amount of cash you have in the bank. There are several libraries for generating graphs with PHP, but I [...]]]></description>
			<content:encoded><![CDATA[<p>A requested feature I recently implemented was the ability to view your character&#8217;s progress in a chart. For example, you can view how quickly you&#8217;ve leveled for the past month, or see the fluctuations in the amount of cash you have in the bank.</p>
<p>There are several libraries for generating graphs with PHP, but I went with <a href="http://phplot.sourceforge.net/" target="_blank">PHPlot</a>. It is easy and highly customizable. Other graphing packages, such as <a href="http://www.aditus.nu/jpgraph/" target="_blank">JpGraph</a> look like they would make more attractive graphs, but are either more complicated and/or not free for commercial use. I was only concerned with making bar graphs, but others are supported by PHPlot and most of the other packages.</p>
<p>Here is the end result:</p>
<p><img src="/wp-content/images/statgraph.jpg" alt="" /></p>
<p>And here is the PHP that generates it:</p>
<pre><code class="php">
// This is to format the x values so that they decrement from left to right
function format_x_value($value, $numDays) {
	return $numDays - $value;
}

        // Every day at midnight, we insert a row in the table StatLog with the current
        // fighting stats, money, health, and level
	$query = "SELECT * FROM StatLog WHERE UserId='".$_SESSION["Id"]."' ORDER BY Date ASC";
	$result = mysql_query($query);

	if ($result) {
		$stat = "Level";
		if (isset($_GET["stat"])) {
			$stat = $_GET["stat"];
			if ($stat == "Potency" || $stat == "Girth" || $stat == "Resp" || $stat == "Level"
                            || $stat == "MoneyBank" || $stat == "TotalHealth" || $stat == "Total") {
				// no op
			} else {
				// not acceptable stat specified - use level by default
				$stat = "Level";
			}
		}

                // Use an array of arrays to make a bar graph with PHPlot
		$data = array();
		$index = 0;
		$numDays = mysql_num_rows($result);

		while ($row = mysql_fetch_assoc($result)) {
			if ($stat == "Total") {
				$data[$index] = array('', $index, $row["Potency"]+$row["Resp"]+$row["Girth"]);
			} else {
				$data[$index] = array('', $index, $row[$stat]);
			}
			$index++;
		}

		$plot = new PHPlot();
		// Only get one x tick per record
		$plot-&gt;SetNumXTicks($numDays-1);
		// Use formatting function to reverse number ordering
		$plot-&gt;SetXLabelType('custom', 'format_x_value', $numDays);
		// Set data to use for graph
		$plot-&gt;SetDataValues($data);
		// Set graph's title
		$plot-&gt;SetTitle($stat . " Log");
		// data-data is the type for a bar graph
		$plot-&gt;SetDataType('data-data');
		// Set x-axis title
		$plot-&gt;SetXTitle("Days Ago");
		// Set y-axis title
		$plot-&gt;SetYTitle($stat);
		$plot-&gt;SetDrawPlotAreaBackground("true");
		// Make bg transparent
		$plot-&gt;SetBackgroundColor('yellow');
		$plot-&gt;SetTransparentColor('yellow');
		// Set plot bg color
		$plot-&gt;SetPlotBgColor("DarkGreen");
		$plot-&gt;DrawGraph();
	} else {
		echo mysql_error();
	}
</code></pre>
<p>Then, from another page, the users can select the stat they would like a graph of and it is passed along like so:</p>
<pre>&lt;img src="viewgraph.php?stat=Potency" /></pre>
<p>I&#8217;d be interested in hearing about other PHP graphing packages, but for now, I&#8217;m quite happy with these results.</p>
<div style="float: left; width: 140px; height: 21px; overflow: hidden; position: relative; left: 8px;"><script>//<![CDATA[
reddit_url="http://blog.plantwars.com/index.php/2009/02/28/dynamically-generated-graphs-with-php";
//]]&gt;
</script><script language="javascript" src="http://reddit.com/button.js?t=1"></script></div>]]></content:encoded>
			<wfw:commentRss>http://blog.plantwars.com/index.php/2009/02/28/dynamically-generated-graphs-with-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

