I’m a big fan of Fedora Linux and have been a user since the Red Hat days. I cut my Linux teeth on Fedora Core 1 (I still have the install discs). Though I’ve tried many other distros, I tend to return to Fedora.
Fedora 10 was released a few days ago. I just installed it, and decided to address a few common issues typical users may face. A few of you may remember that I did the same thing for Fedora Core 6. Here we go.
For the purposes of this guide, I’m using GNOME on an i686 machine. Read more
Disclaimer: some users have reported that this method does not work properly. Rest assured that it works, but I only recommend it for people comfortable with the Terminal. There’s a lot of room for error.
Please back up your Address Book before attempting this method. I am not responsible for lost data.
Here is a little tip for you Mac users out there. We have written about the awesome, cross-platform Dropbox service before (here and here), and while it’s great for keeping ordinary files and folders in sync across the Internet, there are a few more clever uses for it.
With a tiny bit of command-line magic, you can easily keep your Mac OS X Address Book backed up online and synced to other Macs. Here’s how: Read more
UPDATE: ADrive no longer has any free plans.
In continuing our online storage series, today we’re going to look at ADrive, which offers a whopping 50GB of free storage. So far we have taken a look at:
Note: In addition to the free plan, ADrive also offers paid plans with additional features and storage space. For this article, I’m using the free version. Read more
Ah, this is sneaky. You may think that a web site can’t read form fields until you hit the submit button, but this is not the case. Using AJAX, a site can read form data at any time. This could be used for nefarious purposes, but I’m presenting here for two reasons: 1) to let people know that it can be done and 2) to show people how to do it for legitimate purposes. What’s a legitimate use of this? Logging, mostly… a lot of work goes into studying why users may fill out only the first page of a form. If you log the data regardless of whether a user clicked submit, you can study user behavior and possibly improve your form.
This tutorial assumes the following: you have a web server running PHP 5 (or greater) and MySQL 5 (or greater) with the mysqli extension installed. There are several parts to how this works:
1. savedata.php: A processing page that grabs posted variables (e.g. savedata.php?variable=value).
2. db.php: A database interface file (usually contained above the document root, contains passwords and save logic).
3. index.php: The HTML page containing the form.
4. The prototype JavaScript library. This is a very handy library that’s pretty easy to use.
Here’s an image showing how these files are organized in their folder structure. /html is the document root of the site: all browser requests are directed in there. /lib is above the document root… only PHP can make calls inside that folder. That’s were we put our database connection logic, including usernames and passwords.
The files used in this demo are listed below, but because scripts tend to get buggy when they’ve undergone conversion to/from html-entities, I’m zipping up the files and uploading them here.
Stealth Submit Sample Files.zip
You should be able to unload the html and lib directories to your web server. Point your DocumentRoot at the html directory; be sure to run the SQL commands included at the top of the db.php file so your database looks the way that this script expects it to.
For the use of visibility, the contents of these files is included below:
<?php
/*
Test this page by hitting it in a browser with variables:
https://your_domain/savedata.php?first_name=Bart&last_name=Simpson&age=11&home_town=Springfield&job=Punk
*Add &debug=1 to the url to print out verbose messages.
*/
include_once($_SERVER['DOCUMENT_ROOT'] . "/../lib/db.php");
$debug = $_REQUEST['debug'];
$debug_msg ="<p>The following variables were passed:</p><hr/>";
// Harvest all form data: this works for posts and gets.
foreach ($_REQUEST as $var => $value) {
$debug_msg .= "<b>$var</b>: $value<br/>";
$form_data[$var] = $value;
}
if ($debug) {
echo $debug_msg . "<hr/>";
}
$result = save_user_data($form_data);
if ($debug) {
if ($result) {
echo "Data saved successfully. Id: $result";
} else {
echo "Error saving data.";
}
}
?>
<?php
/*
Contains database handle (username/password) and saving functions
Here's the table definition for the table used in this demo:
CREATE DATABASE ajax_demo;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`first_name` char(64) default NULL,
`last_name` char(64) default NULL,
`age` tinyint(3) default NULL,
`home_town` char(64) default NULL,
`job` char(64) default NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM;
GRANT ALL PRIVILEGES ON ajax_demo.* TO 'peter'@'%'
IDENTIFIED BY 'abc123';
*/
// Test regex's here by uncommenting this line and executing this file.
// echo get_name_regex('Bob');
/*-------------------------------------------------------------------------
DEFINE Database constants here
---------------------------------------------------------------------------*/
define("DATABASE_HOST", 'localhost');
define("DATABASE", 'ajax_demo');
define("DEFAULT_USER", 'peter');
define("DEFAULT_USER_PASSWORD", 'abc123');
function connect_db ($user = DEFAULT_USER) {
/*
INPUT: $user
This function allows for multiple handles to be called, e.g. handles for
read-only, write-only, etc. Each user has its own permissions.
mysqli format is mysqli(DATABASE_HOST, USER, PASSWORD, DATABASE);
*/
switch($user) {
case DEFAULT_USER:
$link = new mysqli(DATABASE_HOST, DEFAULT_USER, DEFAULT_USER_PASSWORD, DATABASE);
break;
}
return $link;
}
/*-------------------------------------------------------------------------*/
function save_user_data ($input) {
/*
INPUT:
Hash with values from form, e.g. $input['first_name'].
OUTPUT:
id from database if successful insert; otherwise null.
*/
$link = connect_db();
/* check connection */
if ( mysqli_connect_errno() ) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$sql = "INSERT INTO user
(
first_name,
last_name,
home_town,
job,
age
) VALUES (
?,
?,
?,
?,
?
)";
$statement = $link->prepare($sql);
if (!$statement) {
printf('Error - SQLSTATE %s.\n', mysqli_sqlstate($db_connection));
exit();
};
// Filter data (regex's, validate, etc)
$first_name = get_name_regex($input['first_name']);
$last_name = get_name_regex($input['last_name']);
$home_town = get_name_regex($input['home_town']);
$job = get_name_regex($input['job']);
$age = get_integers_only_regex($input['age']);
// Bind-parameters: s=string, i=integer, d=double, b=blob
$statement->bind_param('ssssi', $first_name, $last_name, $home_town, $job, $age);
$statement->execute();
if ($link->error) {
echo $link->error;
}
if ($link->insert_id) {
$result = $link->insert_id;
}
echo
$link->close();
return $result;
}
/*====== DATA FILTERING and VALIDATION =============================*/
function get_name_regex ($input) {
$pattern = '/(;|\||`|=|--|\/|\.|>|<|&|^|"|'."\n|\r".'|{|}|[|]|\)|\(|[0-9])/i';
$input = preg_replace($pattern, ' ', $input);
return trim(ucfirst($input));
}
// Given any input, we only want a valid integer here, e.g. 2.24 --> 2
// Specify the length desired.
function get_integers_only_regex ($input, $len = 100) {
// $input = (int)$input; // typecast will fail if you have a zip w/ a leading 0, e.g. 09921
if ($len > 0) {
$pattern = '/\D/';
$input = preg_replace($pattern, '', $input);
$input = substr($input, 0, $len);
}
return $input;
}
?>
<html>
<head><title>Stealth Submit</title>
<script src="/js/prototype-1.6.0.3.js"></script>
<script language = "Javascript">
function saveData() {
new Ajax.Request('savedata.php', {
method: 'post',
parameters: {
// $('form_id').serialize(true)
first_name: document.getElementById('first_name').value,
last_name: document.getElementById('last_name').value,
home_town: document.getElementById('home_town').value,
age: document.getElementById('age').value,
job: document.getElementById('job').value
}
});
}
</script>
</head>
<body onunload="saveData()">
<form id="form_id" method="post" action="action.php">
First Name: <input type="text" id="first_name" name="first_name"><br/>
Last Name: <input type="text" id="last_name" name="last_name"><br/>
Age: <input type="text" id="age" name="age"><br/>
Hometown: <input type="text" id="home_town" name="home_town"><br/>
Job: <input type="text" id="job" name="job"><br/>
<input type="submit" value="Submit" />
</form>
<a href="https://www.google.com/">Arbitrary Other Page... FORM NOT SUBMITTED</a>
</body>
</html>
In the land of virtual machines, there are a few big names, such as VMware and VirtualPC. However, there is a slightly lesser-known contender worth examining – VirtualBox.
I have no intention of pitting the various virtualization tools head-to-head, or to label any one of them as the subjective best, but if all you’re looking for is a free and easy way to run virtual copies of operating systems, VirtualBox has you covered.
VirtualBox runs on Windows, Mac OS X, Linux, and OpenSolaris, and can support a massive number of guest operating systems. DOS? Check! OS/2? Yep! Vista? Of course.
Best of all, VirtualBox is completely free. You can choose to download either a compiled binary or the open-source edition.
I’m going to walk through the process of setting up a new virtual machine. The host OS is Mac OS X, using VirtualBox 2.0.4. Read more
To continue in the spirit of free products, Apress.com is giving away digital downloads of The Definitive Guide to Linux Network Programming.
The book has a list price of $49.99, and is available for free download here.
Update: the download link appears to be down on Apress right now (due to massive traffic). Here is a temporary download link.
For those of you who don’t like staring at computer screens too long, you can purchase a hard copy on Amazon for $35 (Amazon link). It has pretty good reviews on Amazon so far, so this 400-page book is certainly worth adding to your arsenal.
Enjoy.