<?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>PHP Archives - Brandon Checketts</title>
	<atom:link href="https://www.brandonchecketts.com/archives/category/php/feed" rel="self" type="application/rss+xml" />
	<link>https://www.brandonchecketts.com/archives/category/php</link>
	<description>Web Programming, Linux System Administation, and Entrepreneurship in Athens Georgia</description>
	<lastBuildDate>Sat, 30 Aug 2025 02:39:55 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>AWS CodeDeploy Troubleshooting</title>
		<link>https://www.brandonchecketts.com/archives/aws-codedeploy-troubleshooting</link>
					<comments>https://www.brandonchecketts.com/archives/aws-codedeploy-troubleshooting#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Sat, 30 Aug 2025 02:38:05 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Linux System Administration]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://www.brandonchecketts.com/?p=1295</guid>

					<description><![CDATA[<p>CodeDeploy with AutoScalingGroups is a bit of a complex mess to get working correctly. Especially with an app that has been working and needs to be updated for more modern functionality Update the startups scripts with the latest versions from https://github.com/aws-samples/aws-codedeploy-samples/tree/master/load-balancing/elb-v2 I found even the latest scripts there still not working. My instances were starting [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/aws-codedeploy-troubleshooting">AWS CodeDeploy Troubleshooting</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>CodeDeploy with AutoScalingGroups is a bit of a complex mess to get working correctly. Especially with an app that has been working and needs to be updated for more modern functionality</p>
<p>Update the startups scripts with the latest versions from https://github.com/aws-samples/aws-codedeploy-samples/tree/master/load-balancing/elb-v2</p>
<p>I found even the latest scripts there still not working. My instances were starting up then dying shortly afterward.  CodeDeploy was failing with the error</p>
<p><code><br />
LifecycleEvent - ApplicationStart<br />
Script - /deploy/scripts/4_application_start.sh<br />
Script - /deploy/scripts/register_with_elb.sh<br />
[stderr]Running AWS CLI with region:<br />
[stderr][FATAL] Unable to get this instance's ID; cannot continue.<br />
</code></p>
<p>Upon troubleshooting, I found that common_functions.sh has the get_instance_id() function that was running this curl command to get the instance ID</p>
<p><code><br />
curl -s http://169.254.169.254/latest/meta-data/instance-id<br />
</code></p>
<p>Running that command by itself while an instance was still running returned nothing, which is why it was failing.</p>
<p>It turns out that newer instances use IMDSv2 by default, and it is required (no longer optional). With that configuration, this curl command will fail.  In order to fix, this, I replaced the get_instance_id() function with this version:</p>
<pre>
# Usage: get_instance_id
#
#   Writes to STDOUT the EC2 instance ID for the local instance. Returns non-zero if the local
#   instance metadata URL is inaccessible.

get_instance_id() {
    TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" -s -f)
    if [ $? -ne 0 ] || [ -z "$TOKEN" ]; then
        echo "[FATAL] Failed to obtain IMDSv2 token; cannot continue." >&2
        return 1
    fi

    INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id -s -f)
    if [ $? -ne 0 ] || [ -z "$INSTANCE_ID" ]; then
        echo "[FATAL] Unable to get this instance's ID; cannot continue." >&2
        return 1
    fi

    echo "$INSTANCE_ID"
    return 0
}
</pre>
<p>This version uses the IMDSv2 API to get a token and uses that token to get the instance-id</p>
<p>With that code replaced, the application successfully registered with the Target Group and the AutoScaling group works correctly</p>
<p>Alternatively (and for troubleshooting), I was able to make IMDSv2 Optional using the AWS Console, and via CloudFormation with this part of the Launch Template:</p>
<pre>
Resources:
  MyLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: my-launch-template
      LaunchTemplateData:
        ImageId: ami-1234567890abcdef0
        InstanceType: t4g.micro
        MetadataOptions:
          HttpTokens: optional
</pre>
<p>The post <a href="https://www.brandonchecketts.com/archives/aws-codedeploy-troubleshooting">AWS CodeDeploy Troubleshooting</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/aws-codedeploy-troubleshooting/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Scripts published for calculating Sales Tax in Texas from Stripe Transaction exports</title>
		<link>https://www.brandonchecketts.com/archives/sales-tax-from-stripe-transactions-report</link>
					<comments>https://www.brandonchecketts.com/archives/sales-tax-from-stripe-transactions-report#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Fri, 30 Aug 2024 23:29:28 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">https://www.brandonchecketts.com/?p=1180</guid>

					<description><![CDATA[<p>Following up from my previous complaints about Texas collecting back Sales Tax for Saas companies,, I put quite a bit of time into writing some PHP scripts to calculate the Texas Sales Tax due and complete their forms. Looking through the actual Stripe transaction detail and determining the sales tax due will save our company [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/sales-tax-from-stripe-transactions-report">Scripts published for calculating Sales Tax in Texas from Stripe Transaction exports</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Following up from my previous complaints about <a href="https://www.brandonchecketts.com/archives/texas-collecting-sales-tax-on-saas">Texas collecting back Sales Tax for Saas companies</a>,, I put quite a bit of time into writing some PHP scripts to calculate the Texas Sales Tax due and complete their forms.</p>
<p>Looking through the actual Stripe transaction detail and determining the sales tax due will save our company tens of thousands of dollars from the original estimated figures that our accountant calculated.</p>
<p>I&#8217;m releasing some of the PHP scripts that I wrote for this on GitHub in case anybody else may find them useful.  They are pretty plain PHP, so hopefully are straightforward enough to follow.</p>
<p>Head on over to <a href="https://github.com/bchecketts/stripe-sales-tax-aid">https://github.com/bchecketts/stripe-sales-tax-aid</a> if that would be useful for you.  Comment below or make Github Issues if you have something to share.</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/sales-tax-from-stripe-transactions-report">Scripts published for calculating Sales Tax in Texas from Stripe Transaction exports</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/sales-tax-from-stripe-transactions-report/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unexpected Behavior with PHP DateTime::createFromFormat(&#8216;U.u&#8217;)</title>
		<link>https://www.brandonchecketts.com/archives/unexpected-behavior-with-php-datetimecreatefromformatu-u</link>
					<comments>https://www.brandonchecketts.com/archives/unexpected-behavior-with-php-datetimecreatefromformatu-u#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Tue, 10 Oct 2023 13:54:59 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://www.brandonchecketts.com/?p=1101</guid>

					<description><![CDATA[<p>I recently came across what felt like a Bug in PHP and was about to file a bug report. I found a couple of people talking about workarounds, but no explanation about why this &#8220;bug&#8221; exists and is allowed to persist. Hopefully this post helps to explain this unintuitive behavior. The problem has to do [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/unexpected-behavior-with-php-datetimecreatefromformatu-u">Unexpected Behavior with PHP DateTime::createFromFormat(&#8216;U.u&#8217;)</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I recently came across what felt like a Bug in PHP and was about to file a bug report. I found a <a href="https://stackoverflow.com/questions/17909871/getting-date-format-m-d-y-his-u-from-milliseconds">couple</a> of people talking about workarounds, but no explanation about why this &#8220;bug&#8221; exists and is allowed to persist. Hopefully this post helps to explain this unintuitive behavior.</p>
<p>The problem has to do with the <a href="https://www.php.net/manual/en/datetime.createfromformat.php">PHP DateTime::createFromFormat()</a> function. The desire here is usually to create a DateTime object that represents a precise point in time, up to 1/100,000th of a second. This code would normally work as expected:</p>
<p><code><br />
$time = microtime(true);<br />
$dateTimeObj = DateTime::createFromFormat('U.u', $time);<br />
echo $dateTimeObj->format('Y-m-d H:i:s.u')."\n";<br />
</code></p>
<p>However, I was observing a problem that occurred infrequently that said</p>
<h3>PHP Fatal error:  Uncaught Error: Call to a member function format() on bool</h3>
<p>So somehow, despite working the vast majority of the time, the $dateTimeObj would sometimes return a boolean (false) instead of a DateTime object.</p>
<p>After some looking into the failed cases, I found that the time 1696832681.000019 return false, but 1696832681.000119 would work as expected. The difference there is 100 microseconds apart.  Clearly 0.000019 is close to zero, and somewhere being rounded down, and unexpectedly causing a problem.   The <a href="https://www.php.net/manual/en/datetimeimmutable.getlasterrors.php">DateTimeImmutable::GetLastErrors</a> function tells me that the error is about &#8220;Data missing&#8221;</p>
<p><code><br />
calling createFromFormat('U.u') with<br />
float(1696832681.000049)<br />
Array<br />
(<br />
    [warning_count] => 0<br />
    [warnings] => Array<br />
        (<br />
        )</p>
<p>    [error_count] => 1<br />
    [errors] => Array<br />
        (<br />
            [10] => Data missing<br />
        )</p>
<p>)<br />
</code></p>
<p>In order to understand what is occurring, you need to notice that the second argument for DateTime::createFromFormat is expected to be a string. So when using a float as the second argument, PHP internally converts it to a string first.  And converting a high precision float to a string in this case, results it in rounding the float &#8220;1696832681.000049&#8221; to the string &#8220;1696832681&#8221;.  Thus, the createFromFormat function is complaining about the &#8220;Data Missing&#8221; because it is expecting to see the period and microsecond portion of the string.</p>
<p>The fix is fortunately, very simple.  Simply wrap the float around <code>number_format($float, 6, '.', '')</code> which will return a string representation including the six decimal places intended.  It&#8217;s not a elegant looking, but it doesn&#8217;t suffer from the occasional problem of returning false and having a fatal error!</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/unexpected-behavior-with-php-datetimecreatefromformatu-u">Unexpected Behavior with PHP DateTime::createFromFormat(&#8216;U.u&#8217;)</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/unexpected-behavior-with-php-datetimecreatefromformatu-u/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP Sessions with Redis Cluster (using AWS Elasticache)</title>
		<link>https://www.brandonchecketts.com/archives/php-sessions-with-redis-cluster-using-aws-elasticache</link>
					<comments>https://www.brandonchecketts.com/archives/php-sessions-with-redis-cluster-using-aws-elasticache#comments</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Tue, 26 Sep 2017 06:46:20 +0000</pubDate>
				<category><![CDATA[Linux System Administration]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=660</guid>

					<description><![CDATA[<p>I&#8217;ve recently been moving some of our project from a single Redis server (or server with a replica) to the more modern Redis Cluster configuration. However, when trying to set up PHP sessions to use the cluster, I found there wasn&#8217;t a lot of documentation or examples. This serves as a walk-through for setting up [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/php-sessions-with-redis-cluster-using-aws-elasticache">PHP Sessions with Redis Cluster (using AWS Elasticache)</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ve recently been moving some of our project from a single Redis server (or server with a replica) to the more modern Redis Cluster configuration.  However, when trying to set up PHP sessions to use the cluster, I found there wasn&#8217;t a lot of documentation or examples.  This serves as a walk-through for setting up PHP sessions to use a redis Cluster, specifically with Elasticache on AWS.</p>
<p>First, create your Elasticache Redis Instance like so. Note the &#8220;Cluster Mode Enabled&#8221; is what causes redis to operate in Cluster mode.</p>
<p><img decoding="async" src="https://www.brandonchecketts.com/wp-content/uploads/2017/09/Screen-Shot-2017-09-26-at-2.08.37-AM.png" alt="AWS Elasticache Redis Creation" width="600" class="alignnone size-full wp-image-661" srcset="https://www.brandonchecketts.com/wp-content/uploads/2017/09/Screen-Shot-2017-09-26-at-2.08.37-AM.png 1039w, https://www.brandonchecketts.com/wp-content/uploads/2017/09/Screen-Shot-2017-09-26-at-2.08.37-AM-300x269.png 300w, https://www.brandonchecketts.com/wp-content/uploads/2017/09/Screen-Shot-2017-09-26-at-2.08.37-AM-768x687.png 768w, https://www.brandonchecketts.com/wp-content/uploads/2017/09/Screen-Shot-2017-09-26-at-2.08.37-AM-1024x917.png 1024w" sizes="(max-width: 1039px) 100vw, 1039px" /></p>
<p>Once there servers are launched, make note of the <strong>Configuration Endpoint</strong> which should look something like: <code>my-redis-server.dltwen.clustercfg.usw1.cache.amazonaws.com:6379</code></p>
<p>Finally, use these settings in your <code>php.ini</code> file.  The exact location of this file will depend on your OS, but on modern Ubuntu instances, You can place it in <code>/etc/php/7.0/apache2/conf.d/30-redis-sessions.ini</code></p>
<p>Note the special syntax for the save_path where is has <code>seed[]=</code>. You only need to put the main cluster configuration endpoint here. Not all of the individual instances as other examples online appear to use.</p>
<p><code><br />
session.save_handler = rediscluster<br />
session.save_path = "seed[]=my-redis-server.dltwen.clustercfg.usw1.cache.amazonaws.com:6379"<br />
session.gc_maxlifetime = 1296000<br />
</code></p>
<p>That&#8217;s it. Restart your webserver and sessions should now get saved to your Redis cluster.</p>
<p>IIn the even that something goes wrong, you might see something like this in your web server log files:</p>
<p><code><br />
PHP Warning:  Unknown: Failed to write session data (redis). Please verify that the current setting of session.save_path is correct (tcp://my-redis-server.dltwen.clustercfg.use1.cache.amazonaws.com:6379) in Unknown on line 0<br />
</code></p>
<p>The post <a href="https://www.brandonchecketts.com/archives/php-sessions-with-redis-cluster-using-aws-elasticache">PHP Sessions with Redis Cluster (using AWS Elasticache)</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/php-sessions-with-redis-cluster-using-aws-elasticache/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Getting Ubuntu 14.04 php5enmod to understand module priority</title>
		<link>https://www.brandonchecketts.com/archives/getting-ubuntu-14-04-php5enmod-to-understand-module-priority</link>
					<comments>https://www.brandonchecketts.com/archives/getting-ubuntu-14-04-php5enmod-to-understand-module-priority#comments</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Mon, 06 Oct 2014 04:13:00 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=570</guid>

					<description><![CDATA[<p>Usage of Debian&#8217;s php5enmod module doesn&#8217;t seem to be documented anywhere except from the command line when calling it without any arguments: user@host:~# php5enmod WARNING: usage: php5enmod [ -s ALL&#124;sapi_name ] module_name [ module_name_2 ] Unfortunately, that provides no information on how to customize the priority of a module when enabling it. Some others seem [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/getting-ubuntu-14-04-php5enmod-to-understand-module-priority">Getting Ubuntu 14.04 php5enmod to understand module priority</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Usage of Debian&#8217;s php5enmod module doesn&#8217;t seem to be <a href="https://www.google.com/search?q=php5enmod+documenation" title="documented anywhere">documented anywhere</a> except from the command line when calling it without any arguments:</p>
<p><code>user@host:~# php5enmod<br />
WARNING:<br />
usage: php5enmod [ -s ALL|sapi_name ] module_name [ module_name_2 ]<br />
</code></p>
<p>Unfortunately, that provides no information on how to customize the priority of a module when enabling it.  Some others seem to think that you should be able to provide a priority level on the command line, but that <a href="https://bugs.launchpad.net/ubuntu/+source/php5/+bug/1273225">doesn&#8217;t</a> <a href="https://lists.ubuntu.com/archives/ubuntu-server-bugs/2014-January/106184.html">work</a>.</p>
<p>It took some digging into the bash scripts to figure out how to make it work.  The trick is to add a comment in the .ini file for the module.  The comment must contain a very specific format of:</p>
<p><code><br />
zend_extension = /usr/lib/php5/20121212/ioncube_loader_lin_5.5.so<br />
; priority=1<br />
</code></p>
<p>The &#8216;priority&#8217; line must be in that format exactly and most not contain any other spaces or characters.  The line must start with a semicolon, followed by a space, followed by priority=, and finally the desired priority level.  The only space on the line must be between the semicolon and the word &#8216;priority&#8217;.</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/getting-ubuntu-14-04-php5enmod-to-understand-module-priority">Getting Ubuntu 14.04 php5enmod to understand module priority</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/getting-ubuntu-14-04-php5enmod-to-understand-module-priority/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Fix For Amazon API Error: Your request is missing required parameters. Required parameters include AssociateTag.</title>
		<link>https://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag</link>
					<comments>https://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag#comments</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Thu, 03 Nov 2011 21:09:41 +0000</pubDate>
				<category><![CDATA[Amazon APIs]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=509</guid>

					<description><![CDATA[<p>Users of Amazon&#8217;s Product Advertising API will begin seeing the following error as of about November 1st: Your request is missing required parameters. Required parameters include AssociateTag. This is due to changing requirements to the Product Advertising API. The AssociateTag parameter is now a required and validated field. You can see in the list of [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag">Fix For Amazon API Error: Your request is missing required parameters. Required parameters include AssociateTag.</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Users of Amazon&#8217;s Product Advertising API will begin seeing the following error as of about November 1st:</p>
<p>Your request is missing required parameters. Required parameters include AssociateTag.</p>
<p>This is due to changing requirements to the <a href="https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html">Product Advertising API</a>.  The AssociateTag parameter is now a required and validated field.  You can see in the <a href="https://affiliate-program.amazon.com/gp/advertising/api/detail/api-changes.html">list of changes</a> that it is the first thing mentioned.</p>
<p>These changes are made to keep the Product Advertising API in line with its purpose of driving affiliate sales through the Amazon.com website.   The AssociateTag is a tag generated from your <a href="https://affiliate-program.amazon.com/gp/associates/network/main.html">Amazon Associates account</a>.  </p>
<p>So far, it looks like the tag is not entirely validated to your account.  I&#8217;ve had luck using fictitious tags such as <strong>aztag-20</strong>.</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag">Fix For Amazon API Error: Your request is missing required parameters. Required parameters include AssociateTag.</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag/feed</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>KnitMeter.com Has Been Upgraded</title>
		<link>https://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded</link>
					<comments>https://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Fri, 25 Mar 2011 03:06:47 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Websites]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=485</guid>

					<description><![CDATA[<p>KnitMeter Has Been Upgraded KnitMeter.com was originally started over four years ago in December of 2007 as a small project that my wife thought would be useful. Since then, the site hasn&#8217;t changed much, but it has managed to grow to thousands of users who have knit nearly 20 thousand miles of yarn. I&#8217;ve received [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded">KnitMeter.com Has Been Upgraded</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="https://knitmeter.com/images/logo-50x50.png" width="50" height="50" alt="KnitMeter Logo" style="float:left;" /></p>
<h1 style="padding-left:80px;">KnitMeter Has Been Upgraded</h1>
<p><a href="https://knitmeter.com/">KnitMeter.com</a> was originally started over four years ago in December of 2007 as a small project that my wife thought would be useful.  Since then, the site hasn&#8217;t changed much, but it has managed to grow to thousands of users who have knit nearly 20 thousand miles of yarn.  I&#8217;ve received numerous requests and have finally gotten a chance to impliment what many of you have been requesting for a while now.  New features on the site include:</p>
<ul class="dots">
<li>Users can now add entries for <strong>knitting</strong>, <strong>crocheting</strong>, and <strong>spinning</strong></li>
<li>Completely new and modernized design and logo</li>
<li>You can customize your widgets directly on KnitMeter.com rather than editing the code for the widget on your website</li>
<li>The website and the <a href="https://apps.facebook.com/knitmeter/">KnitMeter Facebook Application</a> are now completely integrated.  Entries added in one will be displayed and counted in the other</li>
<li>The Facebook application can (again) publish your entries to your news feed, but only when you tell it to</li>
<li>You can chose to make your profile public, which will display some of the most recent entries on the KnitMeter home page with a link to your website</li>
<li>Added several new timeframes, including specific calendar years  (ie: I knit 4.3 miles in 2010)</li>
<li>Numerous technical changes that should make the site faster to use and make it easier to make future changes</li>
</ul>
<p>These new features have been rolled out over the past couple of weeks.  I appreciate the patience of those who have dealt with a few bugs over that time, and I believe that everything should be pretty bug-free now.  I encourage you to check out the new site and to start adding up the mileage for your own projects.   The next major milestone will be when we have gone through enough yarn to go around the earth (about 24,901 miles).  At the present rate, we should hit that figure in about 3-5 months. </p>
<p>Happy Knitting, Crocheting, and Spinning,<br />
Brandon Checketts<br />
<a href="https://knitmeter.com/">KnitMeter.com</a></p>
<p>The post <a href="https://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded">KnitMeter.com Has Been Upgraded</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Website Performance: Tables Versus CSS</title>
		<link>https://www.brandonchecketts.com/archives/website-performance-tables-versus-css</link>
					<comments>https://www.brandonchecketts.com/archives/website-performance-tables-versus-css#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Sat, 16 Oct 2010 21:00:18 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Website Performance]]></category>
		<category><![CDATA[Websites]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=478</guid>

					<description><![CDATA[<p>Most website designers have been using CSS for page layout for several years now, but I occasionally see some websites that continue to use HTML tables for layout. As I&#8217;ve been focusing on website performance lately, I&#8217;ve found some references that modern browsers render sites using tables for layout slower than they do sites that [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/website-performance-tables-versus-css">Website Performance: Tables Versus CSS</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Most website designers have been using CSS for page layout for several years now, but I occasionally see some websites that continue to use HTML tables for layout.  As I&#8217;ve been focusing on website performance lately, I&#8217;ve found some references that modern browsers render sites using tables for layout slower than they do sites that use CSS.  I decided to investigate and confirmed that there are many possible situations where sites using large tables will appear to load much slower than those using CSS.  I put together two pages to confirm:</p>
<p>This page uses &lt;div&gt; elements for layout<br />
and<br />
This pages uses a large table for layout</p>
<p>On both pages I&#8217;ve added a 5-second sleep near the end of the page to show what might happen if the server was slow, if there were network problems, or any other number of things may have happened.</p>
<p>Notice that the page created using a table changes a lot after the delay.  I&#8217;ve tried it in Firefox 3 which extends the main (yellow) content section all of the way to the right until it receives the rest of the document, at which point it has to shrink that part to make room for the section on the right.   Internet Explorer behaves even worse.  It leaves a blank white page until after the delay, at which point it draws the whole table.</p>
<p>By contrast, the page created with CSS positioning shows all of the content above the delay and has it in the correct position.  When the rest of the document is sent it just fills in the appropriate content, but doesn&#8217;t have to re-arrange anything on the page.</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/website-performance-tables-versus-css">Website Performance: Tables Versus CSS</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/website-performance-tables-versus-css/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Script to Import Static Pages into GetSimple CMS</title>
		<link>https://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms</link>
					<comments>https://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms#comments</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Thu, 13 May 2010 04:30:52 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Websites]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=457</guid>

					<description><![CDATA[<p>I&#8217;ve recently been impressed with a very simple Content Management System called GetSimple. It provides just the very basics that allows a user to edit their own website content. For brochure sites with owners who don&#8217;t want the complexity of a larger CMS, I think it is pretty ideal. When I develop a site though, [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms">Script to Import Static Pages into GetSimple CMS</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ve recently been impressed with a very simple Content Management System called <a href="https://get-simple.info/">GetSimple</a>.  It provides just the very basics that allows a user to edit their own website content.  For brochure sites with owners who don&#8217;t want the complexity of a larger CMS, I think it is pretty ideal.</p>
<p>When I develop a site though, I typically have a header and footer, and then all of the content pages exist as PHP files that simply include that header and footer.  Converting a static site like that into the CMS takes a bunch of copy/pasting.  I always try to avoid such tedious jobs, and so developed a script  that will import those static pages into a GetSimple installation.</p>
<p>To run this script, I wanted to import a bunch of files in a &#8216;static&#8217; directory where I had moved all of the static files to.  I then ran this from the command line to import all of the content into GetSimple</p>
<pre>
# for file in `find static -type f`
> do
> ./getsimple_import_file.php $file
> done
</pre>
<p>The script is available as <a href="https://www.brandonchecketts.com/downloads/getsimple_import_file.php">getsimple_import_file.php</a></p>
<p>It takes a little configuration before running it.   It works by simulating the data that you would submit when creating the page through the web interface, so we have to fake the necessary session cookie.  Uncomment the bit in the middle that will display your cookie and run the script once.  You&#8217;ll need to copy your cookie name and value into the script before doing any actual imports.</p>
<p>Once you&#8217;ve done that, you will probably want to change the regular expression that attempts to grab the page title from your file.  You may also want to manipulate how it figures the URL to use.</p>
<p>Feel free to post comments here if  you found this useful, or made any changes  you&#8217;d like to share with other users</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms">Script to Import Static Pages into GetSimple CMS</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms/feed</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Enabling HTTP Page Caching with PHP</title>
		<link>https://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php</link>
					<comments>https://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php#respond</comments>
		
		<dc:creator><![CDATA[Brandon]]></dc:creator>
		<pubDate>Thu, 29 Apr 2010 16:54:30 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Websites]]></category>
		<guid isPermaLink="false">http://www.brandonchecketts.com/?p=454</guid>

					<description><![CDATA[<p>I&#8217;ve been doing a lot of work on BookScouter.com lately to reduce page load time and generally increase the performance of the website for both users and bots. One of the tips that the load time analyzer points out is to enable an expiration time for static content. That is easy enough for images and [&#8230;]</p>
<p>The post <a href="https://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php">Enabling HTTP Page Caching with PHP</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ve been doing a lot of work on <a href="https://bookscouter.com/">BookScouter.com</a> lately to reduce page load time and generally increase the performance of the website for both users and bots.  One of the tips that the <a href="https://addons.mozilla.org/en-US/firefox/addon/3371">load time analyzer</a> points out is to enable an expiration time for static content.  That is easy enough for images and such by using an Apache directive such as:</p>
<pre>
    ExpiresActive On
    ExpiresByType image/gif A2592000
    ExpiresByType image/jpg A2592000
    ExpiresByType image/png A2592000
</pre>
<p>But pages generated with PHP by default have the Pragma: no-cache header set, so that the users&#8217; browsers do not cache the content at all.  In most cases, even hitting the back button will generate another request to the server which must be completely processed by the script.  You may be able to cache some of the most intensive operations inside your script, but this solution will eliminate that request completely.  Simply add this code to the top of any page that contains semi-static content.  It effectively sets the page expiration time to one hour in the future.  So if a visitor hits the same URL within that hour, the page is served locally from their browser cache instead of making a trip to the server.  It also sends an HTTP 304 (Not Modified) response code if the user requests to reload the page within the specified time.  That may or may-not be desired based on your site.</p>
<pre>
$expire_time = 60*60; // One Hour
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + $expire_time));
header("Cache-Control: max-age={$expire_time}");
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', time()));
header('Pragma: public');

if ((!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) && (time() - strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < = $expire_time)) {
    header('HTTP/1.1 304 Not Modified');
    exit;
}   
</pre>
<p>The post <a href="https://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php">Enabling HTTP Page Caching with PHP</a> appeared first on <a href="https://www.brandonchecketts.com">Brandon Checketts</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
