PHP script to send SMS (Text) Messages – Scheduled with Crontab

Recently, I had a need to send a reminder text message at a given time on a daily basis. Creating a PHP script to send a message to a phone is extraordinarily simple, its a mail form that emails the phone in question using the following email address format:

<phone number>@carrierdomain.com

I chose to use PEAR Mail and had my script authenticate with Gmail to personalize the message. If you use the local SMTP service and do not authenticate with an external mail server, your messages will originate from the server’s hostname.

A list of domains for all cell phone carriers can be found here:
Cell Phone Carrier Domains

Once the script was tested and working, it was configured to run at 10:45am using crontab.
Crontab Quick-Reference

Note: This script does not contain error checking.

/*
 * Date created: 08/11/11
 * PEAR Mail script to send a message using SMTP Authentication to send through Gmail.
 */

include("Mail.php");

$recipients = "5555555555@tmomail.net"; //Must use 10-digit number [include area code]
$headers["From"] = "user@gmail.com";
$headers["To"] = "5555555555@tmomail.net"; //T-Mobile
$mailmsg = "This is a text message";

/* SMTP server name, port, user/passwd */
$smtpinfo["host"] = "ssl://smtp.gmail.com";
$smtpinfo["port"] = "465";
$smtpinfo["auth"] = true;
$smtpinfo["username"] = "user@gmail.com";
$smtpinfo["password"] = "password";

/* Create the mail object using the Mail::factory method */
$mail_object =& Mail::factory("smtp", $smtpinfo);

/* Ok send mail */
$mail_object->send($recipients, $headers, $mailmsg);

Bash – MySQL Backup

#!/bin/bash
# Number of days to keep backups
DAYS=14

# Credentials:
BU_HOST="host_name"
BU_DBNAME="database_name"
BU_USER="user_name"
BU_PASS="password"

# Backup location:
BU_PATH="/path/to/dir"

 # Check for connectivity
mysqldump -u $BU_USER -p$BU_PASS -h $BU_HOST --opt $BU_DBNAME > $BU_PATH/$BU_DBNAME-`date -I`.sql;

# Remove old backups
find $BU_PATH -name *.sql -ctime +$DAYS -exec rm -f '{}' ';'
exit 0

Combine this with crontab to enable scheduled remote MySQL dumps.

Apache Error – could not bind to address {::}:80

[root@delorean vservers]# /etc/init.d/httpd start
Starting httpd: (98)Address already in use: make_sock: could not bind to address [::]:80
(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs
                                                           [FAILED]
[root@delorean vservers]#

Either another instance of Apache is already running, or a Perl process is using port 80 and interfering with Apache.

[root@delorean vservers]# killall -9 httpd
#until all Apache processes are killed
[root@delorean vservers]# killall -9 perl
#until all Perl process are killed
[root@delorean vservers]# /etc/init.d/httpd restart

Automated MSSQL Backups to Remote Server

A collegue of mine developed the following Windows Powershell script. On the database (MSSQL) server, the script is configured to be run on a weekly basis by a Windows Scheduled Task and takes a CSV file as a command line argument. Within the CSV are all of the database names and corresponding FTP credentials for a given backup. The script reads the CSV line-by-line, creates a SQL dump for each database, then transfers each dump to a specified location on the remote server. Useful for those who provide FTP access to a web server but not direct access to the database server. Very nice.

#clear screen
cls

#import list of databases and Remote FTP information
#CSV file is in the following format
#database,ftp_server,ftp_user,ftp_password,ftp_path
$list = Import-Csv $args[0] #CSV File Name is passed via command line

#Default Path for Database Backups
$backup_path_base = "C:\backups\"

foreach($entry in $list){
	#Database to backup
	$db_to_backup = $entry.database

	#FTP Information
	$remote_server = $entry.ftp_server
	$ftp_username = $entry.ftp_user
	$ftp_password = $entry.ftp_password
	$ftp_path = $entry.ftp_path

	#full path for database backup
	$backup_location = $backup_path_base + "\" + $db_to_backup

	#check to see if the database backup directory exists
	if(Test-Path $backup_location){
		#directory exists...move along
	} else {
		#create missing directory
	 	New-Item -Path $backup_location -type directory | Out-Null
	}

	[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
	[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
	[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
	[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null

	#create a new server object
	$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"
	$db = $server.Databases[$db_to_backup]
	$db_name = $db.Name

	#generate timestamp for backup file name
	[string]$timestamp = Get-Date -format yyyyMMddHHmmss

	#Set file name of Backup File
	$backup_file_name = $db_to_backup + "_" +$timestamp + ".bak"

	try{
		#Backup the database
		$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
		$smoBackup.Action = "Database"
		$smoBackup.BackupSetDescription = "Full Backup of " + $db_to_backup
		$smoBackup.BackupSetName = $db_to_backup + " Backup"
		$smoBackup.Database = $db_to_backup
		$smoBackup.MediaDescription = "Disk"
		$smoBackup.Devices.AddDevice($backup_location + "\" + $backup_file_name, "File")
		$smoBackup.SqlBackup($server)

		try{
			# Create a FTPWebRequest
			$ftp_uri = "ftp://" + $remote_server + $ftp_path + "/"
			$webclient = New-Object System.Net.WebClient
			$webclient.Credentials = New-Object System.Net.NetworkCredential($ftp_username,$ftp_password)
			$uri = New-Object System.Uri($ftp_uri + $backup_file_name)
			$webclient.UploadFile($uri, $backup_location + "\" + $backup_file_name)
			Remove-Item $backup_location"\"$backup_file_name
		} catch {
			Write-Host "FTP Error!"
		}
	} catch{
		Write-Host "Error Backing Up Database!"
	}
}

Privacy Survey

One of my recent homework assignments involved completing a privacy survey to quantify the number of times my privacy was compromised in the previous seven days. Some example questions were:

“I have picked someone up from or gone into a train station, airport, or bus terminal.”
“I have carried my cell phone.”

Read more

POST PHP Form to Itself

Today, while troubleshooting a customer’s site, I came across a very clean and effective method of combining an HTML form with PHP and allowing the form POST to itself. Method below:

if(!empty($_POST) && $_POST['submit'] == "submit_value"){
    require_once("process_form_script.php");
}
<form action="" class="form_class" method="post">
.
.
.
<input type="submit" value="submit_value" name="submit" />

Concise and effective – very nice.

Delete All Rules from IPTables

iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X

After installing Brute Force Detection, my server decided that connecting from my home Verizon IP was a brute force attempt. Still haven’t figured out why, since I haven’t had so much as a single invalid log-in attempt in establishing an SSH connection, but I had to wipe iptables and start over. Posted the above in case anyone else has the same issue.

Will investigate why the server blocked my desktop and post a summary.

Basic PHP Mail Form

Creating a web page to send an email requires two pages: an HTML form to accept input from the user and a PHP script to process the information, then generate and send the message. In this example, our HTML form is named test.html and our PHP script is named test.php.

test.html:

<html>
<head>
          <title>Basic PHP mail form</title>
          <h1>PHP Mail Form</h1>
</head>
<body>
<form name="basic_mail_form" method="POST" action="test.php">
          <table width="100%" border="0" cellspacing="1" cellpadding="3">
                    <tr>
                              <td width="16%">Subject</td>
                              <td width="82%"><input name="subject" type="text" id="subject" size="50"></td>
                    </tr>
                    <tr>
                              <td>Detail</td>
                              <td><textarea name="detail" cols="50" rows="4" id="detail"></textarea></td>
                    </tr>
                    <tr>
                              <td>Name</td>
                              <td><input name="name" type="text" id="name" size="50"></td>
                    </tr>
                    <tr>
                              <td>Email</td>
                              <td><input name="customer_mail" type="text" id="customer_mail" size="50"></td>
                    </tr>
                    <tr>
                              <td><input type="submit" name="Submit" value="Submit"></td>
                    </tr>
         </table>
</form>
</body>
</html>

test.php:


//message variables
$subject = $_POST['subject'];
$message = $_POST['detail'];
$to = $_POST['customer_mail'];
$from = "info@yourdomain.com";
$header = "From: ".$_POST['name']." <".$from.">";

//generate email
$send_message = mail($to,$subject,$message,$header);

//execute mail() function - send message
if($send_message)
echo "We've recived your contact information";

else
echo "ERROR";

Performance Tuning: General Apache Directives

In general, the directives within this article are specified in the Apache configuration file – /etc/httpd/conf/httpd.conf. However, some directives may be specified within <VirtualHosts> containers or .htaccess files. Please refer to the Apache documentation to determine where a directive may be specified.

AllowOverride/AccessFileName

By default, the AccessFileName directive specifies .htaccess.

“While processing a request, the server looks for the first existing configuration file from this list of names in every directory of the path to the document, if distributed configuration files are enabled for that directory. For example, before returning the document /usr/local/web/index.html, the server will read /.htaccess, /usr/.htaccess, /usr/local/.htaccess and /usr/local/web/.htaccess for directives” -Apache.org

Using the AllowOverride directive, we can prevent Apache from making unnecessary requests for distributed configuration files, improving performance. Once disabled across the filesystem, we can enable the directive for specific directories that require the use of .htaccess files.

Options

Read more

Performance Tuning: Apache Modules

Multi-Processing Modules

MPMs allow Apache to be deployed across a number of platforms and environments (Windows, Mac, Linux, etc.).

“Apache 2.0 extends this modular design to the most basic functions of a web server. The server ships with a selection of Multi-Processing Modules (MPMs) which are responsible for binding to network ports on the machine, accepting requests, and dispatching children to handle the requests.”-Apache.org

By changing the MPM, we can change the way Apache handles web requests and potentially improve performance. In Linux, we can choose from a number of MPM’s, but the most common are prefork and worker. The prefork model uses more resources but provides greater stability, while the worker model increases peformance but requires thread-safe modules and can be susceptible to system crashes.

Read more