Saturday, December 11, 2010

Pure-FTPd and Passwords

I use pure-ftpd as my FTP server, mostly because it was on the first server I managed and I got used to it. I've been having a little difficultly with setting it up on two new cloud computers and I came across this helpful note.

I set up new linux users and then when I tried to connect via FTP I would get a 530 Login authentication failed.

For whatever reason, if you create a new user and want to use it for FTP, the user must have a shell assigned. You can check the shell by looking at the /etc/passwd file and looking at the last parameter. If the user has no valid shell assigned, you can set this with a command like this:

chsh -s /bin/bash theusername

Wednesday, October 20, 2010

PHP to Remote Database Error: "Can't connect to MySQL server on..."

On a new server migration project I am working on I have separate web and database servers. So, I use a private network to connect them. It took me a day to get working, so I am putting up a post to help others in similar situations.

First, just to clarify, I knew it was a web server problem (and not a network or db permissions issue), because I could connect to the MySQL server just fine from the MySQL command line on the web server. But, when I pinged the PHP web page from my browser I'd get this error:

Can't connect to MySQL server on '' (13)

The problem was SELinux, which was installed and crackin' down on Apache rights.

One simple fix:
setsebool -P httpd_can_network_connect=1

More information can be found in this nice article:

SELinux would allow me to connect from the command line just fine. I could even execute the PHP script from the command line and connect fine. But SELinux did not like it when Apache tried to connect to a computer on the network. Hence the policy update, as stated above.

If you have other issues or it appears that your db server is having issues, here are some other MySQL debug tips as well.

Monday, October 18, 2010

Add Text to an Existing PDF Using PHP

I am finishing up on a project right now that fills out a PDF application for a merchant account. The software helps the user through the application process by asking more targeted questions and filling in fields that are known. In order to do this I had found two PHP libraries that work quite well.

The first is FPDF. It is a free PHP library that allows you to create PDFs. It is not a module or binary code, just a straight up PHP script library. Color me impressed. You can download it at

The second bit of code you need is called FPDI. This will import a PDF as a template and allow you to overlay text. It worked quite well for my project as I was taking an existing PDF and filling in fields on top of it. Just like FPDF, it is super easy to install because all it is is a collection of PHP script files. You can download it at

Here is a quick demo by FPDI on how to use these two modules together.

To make it all work I created a flat, PDF version of the template PDF. I removed all of the form fields using Adobe Acrobat. The first run I got an error: "probably uses a compression technique which is not supported". This was easily fixed by saving the PDF as PDF/A using Adobe Acrobat. (Update below.)

If you have any questions, please let me know. I'd be glad to share more of what I learned.

Update (10/22/10): I've learned that saving the PDf as a PDF/A doesn't always solve the error I explained above. What has worked, however, is running Adobe Pre-Flight on the document. If you go to "Advanced" > "Print Production" > "Preflight" and then click on "Analyze and fix", Adobe will work some magic on the document and make it work with FPDI.

Update (1/27/11): FPDI, the free version of the PDF parser, requires the PDF to be version 1.4 or below. To save a PDF in this format, open the document in Adobe Acrobat, click "Save As" and then select the type "PDF, Optimized" then click the "Settings" button and select "Adobe Acrobat 5.0". This will save the PDF in version 1.4, which was last used in Adobe Acrobat 5.0!

Tuesday, October 5, 2010

Removing WordPress LINK: NEXT and PREV

In WordPress, in the HTML HEAD, there are two <link> lines that are present. One is rel="next" and the other is rel="prev". Now, if you have some pages that you don't want just anyone to find (and the private and password-protect features are not appropriate), this little feautre may reveal them to the public.

To remove the LINK data from the HEAD:
  1. First, pull up your template editor by going to Appearance >> Editor.
  2. On the right side is a list of files. Click on "Theme Functions" or "functions.php" to edit it.
  3. At the top, just after "<?php" add these lines of code:
    1. remove_action('wp_head', 'parent_post_rel_link', 10, 0);
    2. remove_action('wp_head', 'start_post_rel_link', 10, 0);
    3. remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);
  4. Click "update file" at the bottom

All done! The link, rel="next" and rel="prev", as well as "start" and "parent", should be all gone from your template.

Friday, October 1, 2010

iPod Touch Battery Life Issue

I love my iPod touch. But it had a problem. After upgrading to the latest and greatest software (iOS 3), the battery life was awful, to say the least. I charged it, set it on the kitchen table in the evening and by morning it was completely dead. Something was very wrong.

The first thing I tried was to disable all push notifications and alerts. And, after charging it up, I left it plugged in for a few extra hours (just in case). Unfortunately, I saw no change in performance. The iPod would die, again, within 24 hours, even if I had not used it. This was getting ridiculous.

I found a blog post that suggested performing a restore. So, I gave this a try. I plugged in the iPod to my laptop, and clicked the restore button in iTunes. After a few warnings and some waiting, the iPod was back to its squeaky-clean state. And I can say that now, after 3 days, that the restore worked and the battery life is back to normal. I haven't charged it in days and it is still going strong.

Bottom line, if your iPod touch's battery life was cut dramatically short after upgrading to iOS 3, try a full restore. Worked for me.

Leave a comment if you've had similar experiences. I'd be interested to hear if it worked for others as well.

Saturday, September 25, 2010


I've been thinking a lot about innovation lately.

There are lots of areas where innovation is strong and advancing. I think of cellular phones, as one great example. Companies like Apple lead the pack, forcing the entire industry to innovate. And it seems like it is a good thing for all of us. I also think of Google and the area of internet services, with major innovation in how we use email and how we search the web. There is also, and this has traditionally been the case, a lot of innovation in the area of art and fashion. You can always get art and fashion that is not innovative, but it is not hard to find people who are pushing new boundaries and forging new styles in these areas.

There are also a lot of sectors where innovation is stagnate or happening at a slow pace. I think of the American automobile industry. There has not been much great innovation in a while and when there is any it is in response to foreign innovation. I also think of telecommunication companies and their service offerings. For instance, home telephone service has had little innovation in quite a while. Plain old telephone is plain old telephone and doesn't look like it is going to change any time soon (which is probably why so many younger people are willing to go without it, now).

So, what areas need innovation? This is my question. And, how can I contribute to these areas, not being a CEO of a major company? How can I use my talent and drive to affect change in these areas that desperately need innovation? These are the questions I've been exploring, lately...

Thursday, September 2, 2010

A Better Browser

This is my PSA to help the world rid itself of bad browsers:

So I just wrapped up major development on a 3-month project and I am stoked to be done. But, I am also more and more convinced of Internet Explorer's ... deficiency.

Now there are the normal "quirks" with IE that every web designer runs into (e.g., version 7's inline-block problem). These "features" are annoying and I have to deal with them often, but at least there are a number of known work-arounds to help me.

There is one major thing that I've come to see about IE in these past 3 months for which there are no work-arounds. It is dreadfully slow and clunky. Things that will run smoothly and look great on Chrome, Safari and Firefox, will look awful slow on IE. This last project uses a lot of DHTML and it has a really high level of user interaction, so naturally there are a lot of animations and fading of images, etc. IE just cannot handle it and I've had to remove a lot of animations for people who are visiting the site with IE.

So, now that the browser Google Chrome is celebrating its second birthday, I thought I'd share my thoughts about browsers once again. Use Chrome if you want a fast, responsive, useful browser. I particularly enjoy the streamlined UI. Switch between Chrome and IE and you'll notice MAJOR speed enhancements. I love Chrome and you will, too.

Tuesday, July 20, 2010

Installing Intermediate CA with cPanel

When I saw that the VeriSign EV SSL / TLS certificates required an intermediate CA to be installed, I was worried it was going to be a long and painful process. Well, turns out it is super easy to install.

It seems that some of the modern browsers have no problem when the intermediate CA is not installed, but older ones, on the other hand, don't like it. So, here is how you make your cert work on most browsers.

First, copy the appropriate intermediate CA root bundle from VeriSign. I had a standard EV SSL, so I used the first cert on this page.

Now, log in to cPanel and click on "SSL/TLS Manager" > "Activate SSL on Your Web Site (HTTPS)". Use the drop-down box to select your domain and the domain's certificate should show up (the one you installed at an earlier time, or google "install SSL certificate with cPanel"). Then, you'll see an extra text box at the bottom called "Ca Bundle (CABUNDLE)." Just paste the intermediate CA there and click "Install." Yep, it's that easy.

Wednesday, June 23, 2010

Wildcard SSL on WHM and cPanel

I had the task of implementing a wildcard SSL for a client the other day. I search the web for info on doing this with WHM and cPanel and got a host of wild answers that made it sound difficult to impossible. When I got done, I was surprised by how easy it was. Here is what I did..

By the way, just as a disclaimer, this is from memory. If you have any feedback, let me know in the comments.

  1. Create an account for * (you must have a dedicated IP for the account for
  2. Generate private keys (Log into cPanel > SSL/TLS Manager > Private Keys (KEY)) for the domain *
  3. Generate a signing request (cPanel > SSL/TLS Manager > Certificate Signing Requests (CSR)) for the domain *
  4. Go to your favorite certificate issuer (RapidSSL, for instance) and get your certificate using the CSR you just created
  5. Upload your new certificate from your issuer (cPanel > SSL/TLS Manager > Certificates (CRT)) by pasting it in the box
  6. Install & enable the new certificate (cPanel > SSL/TLS Manager > Activate SSL on Your Web Site (HTTPS)) for (it is missing the * but this is ok)
  7. Everything should be working now, so try it by going to
  8. Create a * sub-domain so that all sub-domains will work (cPanel > Subdomains) directing them to the document root of public_html
  9. Create a folder in public_html for each sub-domain you want to use
  10. Add these lines to your .htaccess file to rewrite the URL:

    # This line should only be in the file once, at the top
    RewriteEngine On

    RewriteCond %{HTTP_HOST} ^mysubdomain\.example\.com$
    RewriteCond %{REQUEST_URI} !^/mysubdomain/
    RewriteRule ^(.*) mysubdomain/$1 [L]

And that should be it. Like I said, I am doing this from memory. But, this is the general outline to getting a wildcard SSL working on cPanel. It does work and is not that hard to get going, contrary to many other posts. If I missed something or did a step wrong, please let me know so I can update this post.


Wednesday, May 19, 2010

Base Dependency, JavaScript and how parseInt() returns 0

I learned today that the parseInt() function in JavaScript actually has a second parameter that is optional. This second parameter defines the number's base. Thus, you can parse an integer that is binary, octal and hexadecimal. However, if you do not define the base, the parseInt function takes a guess at the base instead of defaulting to decimal.

So, if you have a parseInt('08') or parseInt('09'), the function will return 0. This is because it is guessing that these are octal numbers (based on the 0 in front) and then returns a 0 because they are invalid octal numbers.

The fix is simple, define the base. Use parseInt('08',10) or parseInt('09',10) instead. This blog post helped me and has more info on the matter.

Thursday, May 13, 2010

Hash Changing, detecting the Back button in JavaScript

If you use gmail and you are a web developer, you have probably noticed that they use hash or anchor links (e.g., "example.html#hash") to make your browser's back button very effective. These hash or anchor links were designed to bring your browser to a certain position in a page. Often they are used on help pages or FAQ pages to make the browser window scroll to a certain point. But, interestingly, they can also be used to set certain JavaScript states, when configured properly.

In order to monitor the hash state and determine if the browser's back or forward button were hence used, you must set up a polling loop. It will check the current hash against the last hash. If there is a change it will do something magical (whatever you want to do).
<script type="text/javascript">
/* set defaults */
var curHash = window.location.hash;

/* check for a change in hash (back or forward buttons) */
setInterval(function() {
 if (curHash != window.location.hash) {
  curHash = window.location.hash;
  /* -- do what you need to do when the hash changes! -- */
}, 250);

The check time is set to 250 ms. But this can be tweaked for your particular needs.

There is rumors that in HTML 5 there will be a hash onchange event. This will really clean up the code, removing the need for polling. Until then, this is the next best thing.

Update 10/28/13 - Side Note: Checkout HTML5's push state for doing cool things like this w/o the hash. You can have the whole URL reflect a change in the DOM without the browser trying to go out and fetch a new web page. Pretty cool stuff. Some JavaScript frameworks like Backbone support both the hash change and the newer push state methods.

Monday, May 3, 2010

PEAR Mail.php - Failed to add recipient (code: 451)

I decided to use the PEAR mailer for a web project in order to send emails through my SMTP server. However, I was getting a strange error:
Failed to add recipient: [SMTP: Invalid response code received from server (code: 451, response: Temporary local problem - please try later)]

Yikes! That is not a very helpful error. If the server doesn't know what what the response code means, how am I supposed to? Using SSH, I took a look at the exim_rejectlog located at /var/log and found that my mail server didn't particularly care for the source or 'From' email address.

After a bit of trial and error, it became clear that 'From' address must match the SMTP account's address. It is a nice anti-abuse feature (for shared servers) that I wasn't even aware of.

Anyway, if you get this error, it probably could be a number of things, but be sure to check that your 'From' email address matches the email address of the SMTP account you are using to send the email.

Wednesday, April 28, 2010

Page Loading Speed-Up

I found out today that if you have JavaScript and CSS externally linked in your HTML head, the CSS should come first. This will allow browsers to fetch both external files at the same time. I use JavaScript to do some last minute page styling, depending on some parameters and also found that this helped the page flicker.

On a related note, the Page Speed add-on to Firefox is a handy little tool for determining areas for improvement for a website (that's where I learned of this CSS before JS tip).

Monday, April 19, 2010

Blocking Bots and Crawlers without Blocking Search Engines

If you run any high-traffic websites it becomes apparent rather quickly that there are people out there trying to download your entire website (and there are many more people doing it than you would think). The question is, how do you block users with ill intent without blocking the major search engine bots (i.e., Yahoo, Google & Bing)?

The Google-recommended way is to do a reverse DNS look-up using the IP address. Then double-check the reverse DNS with a normal DNS look-up. The explanation is found here. Note that this code will not work alone. If implemented, all regular visitors will be blocked. You must add some code to count the number of visits from a unique IP address and use this information as well.

How is this done in code? Check out this great PHP solution. (Not sure if Bing uses the old msn search bot domain name or not.)

There is one issue that comes up with an implementation like this. By doing this you are blocking all bots and search engine crawlers which are not in your list. In other words, you are helping ensure that no other search engines can index your site. While it does still allow the major search engines to compete on the same level (at least in terms of your site), it is a bit anti-entrepreneurial and anti-competition because it locks-out small search engines and start-ups.

Friday, April 9, 2010

Random exclamation points inserted into emails

I use PHP mail() to send out emails quite often. I recently found out that if you create your email as one long string without line breaks, you'll get random exclamation points in your emails. I was recently pointed towards RFC 2822 section 2.1.1 for the solution. It appears that no line can be longer than 998 characters without a line break.

How do you fix this? (1) The first way is to base-64 encode the data (best solution for plain text emails to retain long lines). Check out this blog for some info on that. (2) The other, much easier way, is to simply insert line breaks in your email (best solution for HTML emails where long lines are not needed). Add a "\r\n" to the end of each line in your email to make sure you never go over 998 characters.

Monday, April 5, 2010

Microsoft Wireless Keyboard 700 v2.0 - Keystroke Problem

I thought I'd post this real quick in case someone else is experiencing the frustrating problem I was having. I have a Microsoft Wireless keyboard and mouse 700 and it has been driving me up the wall lately. The keyboard would miss keystrokes, would occasionally respond with a repeated keystroke and would otherwise be annoying. I tried replacing the batteries, re-syncing and restarting and nothing helped.

Then, I tried moving the receiver device that plugs into my USB port further away and voilĂ : Here I am typing up a storm without getting stressed. It is nice to have a keyboard that works again. Apparently the USB receiver cannot be within a certain distance from my keyboard... maybe I should have read the instruction manual.

Update (6/23/10): The manual states that the mouse & keyboard should be between 8 inches and 4 feet from the receiver.

Update 2 (8/10/10): I've officially given up on this mouse & keyboard. The mouse drains a fresh pair of AA batteries in about two weeks and the keyboard constantly has connectivity problems. I went back to old-fasioned wired replacements, for now.

Wednesday, March 31, 2010

PCI and multiple servers

I noticed that a few web hosting companies out there recommend that you lease two servers when trying to reach PCI compliance. Which leaves me wondering, how can a small business afford to even be PCI compliant if this is a requirement?

PCI DSS compliance requires that "only one primary function is performed per server" (2.2.1). Because "primary function" can be interpreted different ways, on-site auditors (QSAs) will sometimes require 2 servers (one for the web servers and one for the database). The logic is that there is an increase risk for data breaches if there are multiple services on one box, giving a potential hacker multiple avenues of attack.

As a side note, many interpret "one primary function" to mean one collective function (e.g., one server is used for payments and thus can have a web server and database server to achieve this collective function). Moreover, you may be able to mitigate the danger of running too many services by never storing sensitive data in the first place (this is my recommendation).

So how is a small business supposed to do business online if a QSA happens to require 2 or more dedicated servers? A couple of cheap dedicated servers would run you about $300 a month.

I've not run this past a QSA but I wonder, why not use virtualization software like XenServer? Chuvakin and Williams, in their book PCI Compliance, talk about how virtualization can be effectively used to separate sensitive environments from other websites. With virtualization you can create multiple virtual machines (VM) on one server. Each VM acts as a separate server, completely isolated and contained. Each VM has its own resources and cannot take more than its share of CPU or memory. Because of this, for the purposes of PCI compliance, each VM could be considered an isolated server. Each VM could be used for separate tasks and they would be kept entirely isolated. It seems to me that this would be an acceptable solution for everyone involved.

Update: Stumbled across this article about virtualization and PCI compliance. Looks like they are working towards clearing up this area of the PCI DSS. Also, this PCI DSS expert believes that, "just like virtualization, running logical partitions that are segmented from each other doesn't violate what the council is trying to prevent" in requirement 2.2.1. Lastly, this QSA states that "Virtual machines need to be treated just like physical machines when assessing them for PCI
compliance" (pg 7).

Friday, March 19, 2010


"In the clarity of this morning, I'm thankful for sleep cycles that disrupt our progress, for children that stop your work and force you to keep someone you love alive, for the need to stop and eat, to stop and drink water, to stop and talk to friends. We buy billions of dollars in books that help us be more efficient, we praise the profit margin, and all the while, God is trying to slow us down, trying to remind us of what matters and what doesn't, trying to stop our human progress, stop our creation of false Gods." -- Donald Miller

Wednesday, March 17, 2010

BIND, Security and PCI Compliance

I get to go through some of the fun known commonly as PCI Compliance. PCI Compliance is a good thing on the whole, nevertheless, it is time consuming. Today I spent time on my DNS server. I use BIND, the open source name server that is very popular across the net.

Upon a PCI scan I got this warning: "Bind Banner." It was a result of my system telling the world what version it is running. This could help a would-be hacker determine if my system is old and if it is vulnerable to certain security holes.

To tighten it up a bit, I made some edits in my config file at /etc/named.conf

At the end of the "options" section of named.conf, I added these lines:

dnssec-enable no;
version none;
hostname none;

This disables or hides the display of the version number, the BIND hostname and disables DNSSEC (which PCI scans tell me is dangerous, even though it is intended for security).

Now, to check to make sure your BIND version is hidden (be sure to restart BIND, first), enter this into the bash command line:

dig -t txt -c chaos VERSION.BIND

If you want some protection against an easy DoS target, add this to your "external" view in named.conf:

additional-from-auth no;
additional-from-cache no;

"recursion no;" should be in there already and this will prevent your server from being an open DNS server for the world. These extra lines above will go a step further and prevent the display of root name servers for external queries. While this is just your DNS server trying to be helpful, your server should just ignore all external queries that are for domains you don't serve. (More info here.)

PS. Looking for a list of all the available options in BIND? Here is a good one, although there is not a lot of description, it does look complete.

Monday, March 15, 2010

Terms of Service - Don't Add This

Because I run a small business, I have to do everything – marketing, accounting, IT security, legal – on top of the real work of making the web site or application for my clients. When it comes to the big, confusing or time-intensive tasks, though, I am willing to pony up and pay the professionals (like when I do my taxes). Today I decided I should put on one of my many hats and take a look, once more, at my company's Terms of Service (TOS).

Interestingly, I came across this very helpful blog entry about including the famous "we can change this whenever we want and you have to check this website everyday for changes" clause that many businesses add to the top of the TOS. I always wondered about this. It doesn't seem quite fair – is it really legal? Well Eric Goldman argues that it can pretty much make your TOS invalid. Read here for more.

Thursday, February 18, 2010

Resolving Name Server IP Addresses

Ever thought about this? If I want to find the website then my computer begins by contacting the TLD (.com) and finding the authoritative name server for If it is, then how does my computer figure out the IP address for this subdomain? Is there a name server for the name server?

After searching about, I've been educated.

This problem is called circular referencing, for obvious reasons. So, to solve this problem, you register name servers with the same people you register the domain with. You specify the name of the name server and an IP address and they register what's called a glue record. This glue record is stored by the TLD (e.g., .com) name servers so that the IP address of your name server (e.g., can be sent when needed.

Bit 'o knowledge for you.

Need to check your glue records? A quick search on Google for glue record provides promising results, like this site.

Tuesday, February 16, 2010

PHP image manipulation

If you have ever wanted to dynamically create or edit images, GD is a great solution for PHP (and LAMP configurations). I am writing this blog entry mostly because I was amazed at how easy it was to install. I just picked it in easyApache (using WHM) and "tada!" – it works. I can't say that about imagemagick. I've tried and tried to get that bit of software to work (on multiple servers) and it is always a pain. I remember on my first server (hosted by another company) I had requested imagemagick and they even had trouble installing it—the help desk ticket was pretty long by the time it was closed.

Anyway, moral of the story: Go with GD for dynamic image manipulation in PHP.

Monday, February 15, 2010

APC.php not Working

I was getting a new server up and running and wanted to install APC (Alternative PHP Cache). Things were going great. I even ran phpinfo() and noted that APC had an entry. Everything was super, right?

I wanted more confirmation, so I used SSH, located apc.php and copied it to a domain for public access. I wanted to know how well APC was working for me. However, it wouldn't run. It sent back errors and when I tried to debug it I got no where.

Turns out, APC wasn't really doing much of anything. I had PHP installed and running as a CGI instead of an Apache Module. If PHP runs as a CGI, APC closes at the end of each script run and the cache is lost—it doesn't make much sense to use APC in this situation. While runing as a CGI has some security benefits you lose a bit of performance and, more importantly to me, APC doesn't really work.

I use WHM and so I went to "Main >> Service Configuration >> Apache Configuration" and then changed the PHP 5 handler to DSO. This solved the problem and apc.php loaded just fine the next time I tried. And it even had some pretty stats for me to see.

Saturday, February 13, 2010

Easy Ways to Accept Donations Online

There are a lot of options out there to help non-profits accept donations online. I want to briefly mention to different categories of solutions to help people who are trying to figure out what is best for their non-profit or church.

  • Perhaps the easiest solution is to use a service like PayPal. You sign up for an account and give them your account info and you are up and running soon. This is technically called an aggregation service, because you do not need to have any special accounts set up—PayPal has done that and accepts payments on your behalf. Google has a similar solution except that it, unlike PayPal, unfortunately requires donors to have Google checkout accounts. With these types of services you will have to pay higher per-transaction fees (10 to 30 cents) and transaction rates (around 3%).

  • The second option is to get what's called a merchant account. This is a special bank account that allows you to accept credit card payments directly (instead of through an aggregator, like PayPal). This is a process that requires an application and some extra steps to setup, but it is often worth the time. The per-transaction rates are almost always lower this route, but there are monthly service fees that are standard (around $10 to $30). Because of this, merchant accounts best for non-profits who are accepting more than a couple hundred in donations a month (but you'll have to do the math to make sure). The cool thing is that if you decide to get a merchant account, your donor's bank statements will actually have your organization's name next to each donation (as opposed to PayPal or Google).

If you want to accept donations online, the second option is a little trickier (because of security standards called PCI-DSS). But, there are companies out there like BlueFire Donations, which can help make this a breeze, helping get non-profits accepting credit credits online in no time.

Got a question? Post in the comments and I'll do my best to help out.

Friday, January 22, 2010

cURL and SSL

cURL is a nice little extension to PHP. You can read an intro here.

I use cURL a lot. It seems that do a lot of web applications that connect to other servers for transactions (like payment gateways). You can do SSL or HTTPS requests to other web hosts without validating their certificates but you leave yourself open to man-in-the-middle attacks. While this seems unlikely if you are running out of a data center, checking the certificate validity is too easy to skip.

The one thing that you must do for this to work is tell cURL where the CA-bundle (or CURLOPT_CAINFO) is located. I am running CENTOS 5.4 and found CA info at "/etc/pki/tls/certs/ca-bundle.crt". I can enable this with the following two lines added before curl_exec();

curl_setopt($ch, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);

Group Text Messaging - Schedule Text Messages

I wanted to take a moment to promote another site I relaunched yesterday. It is ShortShout and it is a group text messaging platform. I've worked out some pretty low per-message rates to make it an affordable service. It can be used by any group and has some special info for churches who want to do text messaging. Check it out at

One of ShortShout's customers is a marketing team in Michigan led by Denise. Denise told me that she uses the system "to encourage and stay in touch with her friends/team members." Denise, in her own words, "is a motivator and keeps her team focused on their goals" with group text messaging and ShortShout.

Thursday, January 14, 2010

MySQL and mysql_select_db

I was convinced that mysql_select_db() was not working today. I wanted to simultaneously connect to two different databases. However, when I called the mysql_select_db function, it seemed that both connections were changing to the database I specified. I couldn't get one link to stay on the original database while I changed the second link to a new database.

After a little digging around I found a helpful user comment about using mysql_connect. The fourth parameter of this function is "new_link" and if you want to simultaneously have two connections open and both connections use the same credentials, you must set this parameter to TRUE. If you don't, it sees that the credentials are the same and will reuse the same resource link, even if you set a different variable.

So, this:

$conn1 = mysql_connect(HOST, USER, PASS);
mysql_select_db(TABLE_1, $conn1);
$conn2 = mysql_connect(HOST, USER, PASS);
mysql_select_db(TABLE_2, $conn2);

turned into this:

$conn1 = mysql_connect(HOST, USER, PASS, true);
mysql_select_db(TABLE_1, $conn1);
$conn2 = mysql_connect(HOST, USER, PASS, true));
mysql_select_db(TABLE_2, $conn2);

And tada, I could simultaneously connect to two (or more) databases.

Friday, January 8, 2010

jQuery and onKeyUp

jQuery has the method keyup to take the place of the html attribute onkeyup. So, for example, let's say want to run a javascript function each time escape is pushed. You would do this like so:
$(document).keyup(function(event) {
  if(event.keyCode == 27) { // Capture Esc key

With this script anytime a key is pressed and goes up in the body of the document, the function specified runs. Simply replace the keyCode number (27, above) with the number that corresponds to your key (like 13 for enter or 8 for backspace). Remember, you must have jQuery "installed" in order for this to work.