Tips and Tricks About Computers, Web Development, Linux, the Internet and the Like
Computers
jQuery and jQuery UI in your Grease Monkey scripts.
Jul 16th
Not all websites are made equal. Unfortunately, some of those websites are ones we’re required to use. Be it our job, our interests or the undiscovered, web-browsing can be the orgeon trail of the internet. Cultivating the atmosphere to work for us and bringing the right tools along for the journey are essential for survival, if you’re a pioneer.
I’m tired of websites that don’t provide, can’t provide or will never provide. I’ve called in my boys, Stylish and Grease Monkey on the front lines. However, beyond the crazy happenstance that another user might share a solution to your issue on userstyles.org or userscripts.org you could be left in the cold, without the right tools. I won’t go into detail on Stylish in this post but you might not even need it after you see the script.
Since I’m already connected with Google every which way in my life, why not pretend like the Internet is a big party and websites are your friends. Introduce jQuery from Google’s CDN to other friends (websites) that don’t already know jQuery and jQuery UI and make it personal.
That was the driving force behind this Grease Monkey Script, which was derived from mashing together strd6′s script and Joan Piedra’s script with an update to the latest versions of jQuery and jQuery UI.
// ==UserScript==
// @name jQuery and jQuery UI
// @author Tyler "-z-" Mulligan
// @version 0.5
// @namespace http://www.doknowevil.net
// @description jQuery 1.6.2 and jQuery UI 1.8.4 loaded from google's CDN with redmond theme.
// @include http://www.website.com/*
//
// @resource jQuery https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
// @resource jQueryUI https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js
//
// @resource jQueryUICSS http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/jquery-ui.css
//
// @resource ui-bg_inset-hard_100_fcfdfd_1x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png
// @resource ui-bg_gloss-wave_55_5c9ccc_500x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png
// @resource ui-bg_glass_85_dfeffc_1x400.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png
// @resource ui-bg_glass_75_d0e5f5_1x400.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png
// @resource ui-bg_inset-hard_100_f5f8f9_1x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png
// @resource ui-bg_flat_55_fbec88_40x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png
// @resource ui-bg_glass_95_fef1ec_1x400.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png
// @resource ui-icons_469bdd_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource ui-icons_469bdd_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource ui-icons_d8e7f3_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_d8e7f3_256x240.png
// @resource ui-icons_6da8d5_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_6da8d5_256x240.png
// @resource ui-icons_217bc0_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_217bc0_256x240.png
// @resource ui-icons_f9bd01_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_f9bd01_256x240.png
// @resource ui-icons_2e83ff_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_2e83ff_256x240.png
// @resource ui-icons_cd0a0a_256x240.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_cd0a0a_256x240.png
// @resource ui-bg_flat_0_aaaaaa_40x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
// @resource ui-bg_flat_0_aaaaaa_40x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
// ==/UserScript==
var $;
// Inject jQuery into page... gross hack... for now...
(function() {
if (typeof unsafeWindow.jQuery == 'undefined') {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
var jQuery = GM_getResourceText('jQuery');
var jQueryUI = GM_getResourceText('jQueryUI');
script.innerHTML = jQuery + jQueryUI;
head.appendChild(script);
}
GM_wait();
})();
// Check if jQuery's loaded
function GM_wait() {
if (typeof unsafeWindow.jQuery == 'undefined') {
window.setTimeout(GM_wait, 100);
} else {
$ = unsafeWindow.jQuery.noConflict(true);
addUIStyles();
letsJQuery();
}
}
function addUIStyles() {
var head = document.getElementsByTagName('head')[0];
var resources = {
'ui-bg_inset-hard_100_fcfdfd_1x100.png': GM_getResourceURL('ui-bg_inset-hard_100_fcfdfd_1x100.png'),
'ui-bg_gloss-wave_55_5c9ccc_500x100.png': GM_getResourceURL('ui-bg_gloss-wave_55_5c9ccc_500x100.png'),
'ui-bg_glass_85_dfeffc_1x400.png': GM_getResourceURL('ui-bg_glass_85_dfeffc_1x400.png'),
'ui-bg_glass_75_d0e5f5_1x400.png': GM_getResourceURL('ui-bg_glass_75_d0e5f5_1x400.png'),
'ui-bg_inset-hard_100_f5f8f9_1x100.png': GM_getResourceURL('ui-bg_inset-hard_100_f5f8f9_1x100.png'),
'ui-bg_flat_55_fbec88_40x100.png': GM_getResourceURL('ui-bg_flat_55_fbec88_40x100.png'),
'ui-bg_glass_95_fef1ec_1x400.png': GM_getResourceURL('ui-bg_glass_95_fef1ec_1x400.png'),
'ui-icons_469bdd_256x240.png': GM_getResourceURL('ui-icons_469bdd_256x240.png'),
'ui-icons_469bdd_256x240.png': GM_getResourceURL('ui-icons_469bdd_256x240.png'),
'ui-icons_d8e7f3_256x240.png': GM_getResourceURL('ui-icons_d8e7f3_256x240.png'),
'ui-icons_6da8d5_256x240.png': GM_getResourceURL('ui-icons_6da8d5_256x240.png'),
'ui-icons_217bc0_256x240.png': GM_getResourceURL('ui-icons_217bc0_256x240.png'),
'ui-icons_f9bd01_256x240.png': GM_getResourceURL('ui-icons_f9bd01_256x240.png'),
'ui-icons_2e83ff_256x240.png': GM_getResourceURL('ui-icons_2e83ff_256x240.png'),
'ui-icons_cd0a0a_256x240.png': GM_getResourceURL('ui-icons_cd0a0a_256x240.png'),
'ui-bg_flat_0_aaaaaa_40x100.png': GM_getResourceURL('ui-bg_flat_0_aaaaaa_40x100.png'),
'ui-bg_flat_0_aaaaaa_40x100.png': GM_getResourceURL('ui-bg_flat_0_aaaaaa_40x100.png')
};
var style = document.createElement('style');
style.type = 'text/css';
var css = GM_getResourceText ('jQueryUICSS');
$.each(resources, function(resourceName, resourceUrl) {
console.log(resourceName + ': ' + resourceUrl);
css = css.replace( 'images/' + resourceName, resourceUrl);
});
style.innerHTML = css;
head.appendChild(style);
}
// All your GM code must be inside this function
function letsJQuery() {
//alert($); // check if the dollar (jquery) function works
//alert($().jquery); // check jQuery version
$("
<div id='example' class='flora' title='This is my title'>I'm in a dialog!</div>
").dialog({
buttons: {
"Ok": function() {
alert("Ok");
},
"Cancel": function() {
$(this).dialog("close");
}
}
});
}
I also wanted to use this script with Chromium browser, the open-source version of Google Chrome. I found the TamperMonkey Extension for Chrome. Stylish is also available for Chrome.
Generating CSS Based on Images, also SEO-Friendly
Feb 20th
I’ve typed out a lot of CSS that’s focused on using a background image to replace text. I’ve been using a cross-browser CSS trick that’s SEO-friendly, I’m not sure if it’s documented anywhere. I came upon the solution myself when I was searching for a clever way to do this years ago and it’s become the standard method for me. However, I dislike the tedious task of typing out the CSS and referencing the image pixels and at work, I don’t want my developers wasting that time either.
I figured it’d be best to come up with a simple solution, so I started coding something out in bash and it worked:
#!/bin/bash
# css.sh - generate common css and html
# Tyler Mulligan (z@interwebninja.com)
# Last Update: 02/16/2011
# MIT License
create_block_image() {
feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
cbi_css $l
done
feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
cbi_html_a $l
done
feh -lr ${1:-.} | awk '{ print $3" "$4" "$8 }' | sed '1d' | while read l; do N=$((N+1));
cbi_html_div $l
done
}
cbi_css() {
f=${3##*/}
echo "#${f%.*} {
display: block;
background: url('$3') no-repeat 0 0;
width: 0;
height: $2px;
padding-left: $1px;
overflow: hidden;
}"
}
cbi_html_a() {
f=${3##*/}
echo "<a href=\"#\" id=\"${f%.*}\" alt=\"$f\" title=\"$f\">${f%.*}</a>"
}
cbi_html_div() {
f=${3##*/}
echo "
<div id=\"${f%.*}\"></div>
"
}
s=$1; shift; case $s in
--image-block|--cbi|-i) create_block_image $@;;
*) help help;;
esacWhich ouputs something like:
z@zygon:~/scripts/css$ ./css.sh -i img/
#dumbtubes-fav {
display: block;
background: url('img/dumbtubes-fav.png') no-repeat 0 0;
width: 0;
height: 14px;
padding-left: 16px;
overflow: hidden;
}
#submit_new {
display: block;
background: url('img/submit_new.png') no-repeat 0 0;
width: 0;
height: 106px;
padding-left: 244px;
overflow: hidden;
}
#dumbtubes-logo {
display: block;
background: url('img/dumbtubes-logo.png') no-repeat 0 0;
width: 0;
height: 70px;
padding-left: 274px;
overflow: hidden;
}
<a href="#" id="dumbtubes-fav" alt="dumbtubes-fav.png" title="dumbtubes-fav.png">dumbtubes-fav</a>
<a href="#" id="submit_new" alt="submit_new.png" title="submit_new.png">submit_new</a>
<a href="#" id="dumbtubes-logo" alt="dumbtubes-logo.png" title="dumbtubes-logo.png">dumbtubes-logo</a>
<div id="dumbtubes-fav"></div>
<div id="submit_new"></div>
<div id="dumbtubes-logo"></div>
To explain the way this CSS works, it uses the padding-left as the actual width, setting the width 0 and then pushes whatever content you have out of view using overflow:hidden to hit it from view. This makes it easy for search engines, keeping your HTML clean and CSS simple.
The bash script relies of “feh” a lightweight image viewer for linux that outputs a list of images and their dimensions. It also generates some sample HTML to quickly drop in and modify.
This is not an elegant solution and I’m not happy with the fact that it relies on feh. I’ve been slowly getting into python and I was amazed at how fast I was able to recreate this script in Python.
#!/usr/bin/python
# css.py - generate common css and html
# Tyler Mulligan (z@interwebninja.com)
# Last Update: 02/17/2011
# MIT License
from PIL import Image
import sys
import os.path
CSS_FORMAT = """#%s {\n\
display: block;\n\
background: url('%s') no-repeat 0 0;\n\
height: %spx;\n\
width: 0;\n\
padding: %spx;\n\
overflow: hidden;\n\
}\n"""
HTML_A_FORMAT = """<a href="#" id="%s" alt="%s" title="%s">%s</a>\n"""
HTML_DIV_FORMAT = """
<div id="%s">%s</div>
\n"""
css=""
html_a=""
html_div=""
for tf in os.listdir(sys.argv[1]):
f = os.path.join(sys.argv[1],tf)
if os.path.isfile(f) == True :
img = Image.open(f)
fid = os.path.splitext(tf)[0]
(width, height) = img.size[0:2]
css += CSS_FORMAT % (fid,f,height,width)
html_a += HTML_A_FORMAT % (fid,f,fid,fid)
html_div += HTML_DIV_FORMAT % (fid,fid)
print css
print html_a
print html_div This is just the basic idea, I didn’t spend more than 15 minutes on this rewrite, it does what I need it to do so far. It was suggested by friends if I make it any bigger, to look into a templating engine, such as mako. I hope this script can be useful to someone :). PS, HTML_DIV_FORMAT should be on one line, not sure why my syntax highlighter is trying to put it on 3.

Retorting An Extremely Biased View Against Android
Jan 14th
Introduction
Those of you that have been following my blog for a while, know that I’m a big supporter of FOSS and Linux. It should come as no surprise then, that I have an Android phone. It’s not the best on the market by any means, it’s one of the first to appear on AT&T’s network but it gets the job done and I like it more than the iPhone (v2) I owned for 6 months. I’m not oblivious to the Appleverse, at my office, I have a Mac mini and an iPad. As a web architect, I need to make sure different operating systems can work from both a development and user viewpoint.
I’m also a bit of a console nerd, I prefer to automate as many tasks as I can. Apple’s terminal has come in handy at times but the BSD base and lack of a [good] package manager have left me yearning. That said, this is a blog post is more focused on the fragmented Android market and the points made by Marco Arment, who has recently claimed there is too much hardware choice for Androids. His bullet points are dripping with Mac bias and as a Google and Android fan, I’d like to weigh in on his “points”.
Breaking Down His Arguments
Accessory markets never fully develop. People really like cases for their phones, and if the iPhone has 300 cases for it including that gummy pink one they really like, and the Samsung Whocares XL only has a few drab OEM plastic things available, a nontrivial portion of the market will choose the iPhone on that reason alone.
There’s also more practical concerns: batteries, docks, speakers, and other useful accessories are usually phone-specific, and if the manufacturer (and the market) will only care about your phone for three months until the next minor revision comes out, your options will be very limited, both in the store and when you’re traveling and forgot something.
- “Arment”
This is a very trivial point because many Android devices use common ports and standards. Micro USB, micro SD, standard size audio jacks, etc. I’m able to charge my phone with any micro USB cable, even if it’s not the same phone or even device, anything from audio controllers to hardrives can use Micro USB.
An iPhone can only charge with a device from the Appleverse. An audio cable is only a few bucks from Radioshack or amazon.com if you don’t have one already and good stereos have audio ports. If you need to by another stereo just to dock your iPod or your phone, you’re not thinking rationally or hanging out in the wrong room.
There are so many variations in screen size, screen type, physical size, hardware sensors, hardware buttons, and computational performance between devices that developers, including Google itself, have a very hard time making great software for the platform.
I find the statement “Have a very hard time making great software for the platform” ignorant. This makes me think Marco hasn’t even used an Android because he’s apparently overlooked the navigation software, Google maps, Google Goggles, gmail and others.
My phone has a smaller screen, though I’d prefer a larger screen with a kickout keyboard. I don’t think the smaller screen has any major bugs with Google’s software and it’s running Android 2.1. I’m missing out on some features [, none that burden me] but holding out for a dual-core and hopefully a kickout keyboard.
Some people like choice. The buttons are pretty standard across the phone, I’ve seen different orders or positions but it’s pretty easy to recognize because they use similar iconography. Besides, doesn’t having this sort of choice allow consumers to need less accessories if the phone can serve a purpose as one device?
iPhone has one button, which is circular with a square in the center, if it doesn’t do what you want, then you’re either out of luck or need to buy an
Lets look at some Androids (click to enlarge images)





The manufacturers and carriers have very little incentive to maintain the software on devices that are still relatively new and under contract, because they want everyone buying the newest ones instead. We’re already seeing carriers and some manufacturers refusing to release new Android versions to handsets that were launched as recently as 6 months ago, even though most users bought them with 2-year contracts.
This will be moot soon enough anyway, the Android operating system is still fairly new, it’s popular enough amongst manufactures that it’s developing at a rapid pace. It’s not a surprise that carriers don’t want to push updates right away, they are still getting used to it. Android is running across a bunch of different hardware but because of intelligent software design, it’s able to do so. With proper organization of the code and more standard development across phones by companies or consortium, it will become a strong piece of software. Why do you think Linux and Apache are the backbone of many servers, and new open-source languages and software are thriving.
The number of iPhone users claiming insurance purposely breaking their phones to upgrade skyrocketed. Besides that, there are plenty of people willing to drop the cash on a new one. It’s not like Apple gives your old operating system a major upgrade (once) but oh wait, this is what you seem to expect from Android.
Flexibility isn’t well known in the Appleverse because their software only needs to run on very specific hardware. Apple products work best on Apple products. iTunes and I guess Safari (don’t kid yourself Steveo) on Windows increase their market share.
People hate choosing between similar things. The more choice we have at the time of purchase, the more stress we feel making the choice, and the less satisfied we feel afterward because we’re worried that we made the wrong choice.
But weren’t you just arguing that this was what was great about having a single phone design, a thriving accessory market?
Closing Thoughts
If the future battle is for content. Google has the most of it and will figure out ways to get content into its possession. Google is supporting Flash but has been on the forefront of HTML5 supported media since inception. They are setting themselves up to bring the internet towards their own video format, which was pieced together in a matter of days from existing standards when the h.264 vs ogg for HTML5 video debated first started months ago. Steve Jobs got upset that h.264, which his hardware decodes wasn’t chosen and a new format war began.
Don’t expect this change to happen overnight. Dropping flash right now would essentially break the web but as soon as Google can drop flash, it will. They’ve already converted all the youtube videos they can to other formats and now it’s standard when new videos are uploaded.
The pieces are coming together and Android is popping up to serve content in all sorts of unexpected places (nook, cable boxes). Remember, companies have been adopting Android for devices that don’t officially support it yet, these differences have begun to be abstracted as we see better support for tablets in Android 3.0.
This is not an accident and to argue that it’s going to be too different across devices of the future is like arguing against an OS such as Windows on a desktop versus a laptop versus a warship vs an ATM machine. Flexible software running across all different hardware expands the reach. This is something you will never get from Apple, who won’t even legally allow you to run OSX in a virtual machine, however, you can run other OSes inside OS X.
The Appleverse requires total submission, I could not turn on my iPhone or iPad without first connecting them to iTunes, there is no such requirement for Google. You don’t have to associate it with your Google account and you don’t have to give Google your information but if you don’t, functionality may be affected.
Your iPhone accessories won’t save you from the glass ceiling that is hardware dependent software. Arguing that you can jailbreak the phone for more features is admitting Apple is doing something wrong and furthermore, you’re making yourself more prone to an attack by installing software from a rouge app store.
Thomas Edison’s Direct Current was cool when he invented it but Alternating Current goes further and starts less fires.
Henry Ford was quoted saying “Any customer can have a car painted any color that he wants so long as it is black.”

Non-free Art In Open-source (FOSS) Video Games
Jan 14th
Introduction
I’ve been interested in art since I can remember, the marriage of computers and art has always fascinated me. I would spend math classes (sorry Mr. D) fiddling around with my calculator, drawing pixel art and saving them in the storage on my calculator. I would hack up BASIC programs or marvel at ASM based games and sub-shells. Later these activities moved over to computers, websites, software, the internet and open-source video games, such as Nexuiz or Xonotic. My brain has always enjoyed trying to pull the worlds of art and science together but it wasn’t always viewing the two alike.
Originally my feelings about art were 2 dimensional, as I’d expect many to view it. It’s easy for art to be a fleeting glimpse. You see the final product, the lines of the creation process are blurred, the definitions of “source” gets lost.
When I first started contributing 2d art to Nexuiz, I was submitting PSD files. I didn’t realize at the time but I was deterring other artists who were without Photoshop the ability to properly edit the file because of some advanced settings in the file that could not be read by open-source software. This hindered others who were trying to expand on my work or create derivative works.
Now that isn’t a completely fair comparison because source is still being provided, only limited to a number of people. However, the reason I bring it up is because it was the beginning of a turning point for me. As I delved more into Linux and the world of Free Open-Source Software (FOSS), I was realizing how important source is to a community. How source code teaches, how knowledge of techniques are passed on. My involvement with Nexuiz and other (at the time) open-source projects, are what kept this message strong in the back of my head.
On Art in Video Games
Source of some art is almost impossible. A hand draw sketch for example, in the digital world however, things are different and art source becomes a very powerful teaching tool. Often, for the creation of maps for these games is not the most straight forward process. The mapping software and map entities require some critical thinking. The most common way to learn to add a feature to your map if you don’t know how, is to identify a map with the feature you’d like to implement, open its .map source file and study how it was done.
The reason this all came up for me today was because of a popular open-source ioquake-based game called Warsow. The code is licensed under GPL and the art has a proprietary, closed-source license. As a core member of the Xonotic team, we faced the decision of how to license Xonotic when we forked from Nexuiz. This decision was not as easy as you’d think because of ‘techniical’ license issues. The code must be GPL because of its lineage, GPL is not so keen on art. Creative Commons is an art license, not so keen on code. They seem like they’d be a good merger but from what I understood they could cause issues for distribution. We’d have to distribute the code and art as separate packages. In the end we licensed everything under GPL to make things easier for ourselves.
I thought Warsow was facing the same problem and today they had a developer Q & A, I decided to ask about this, pardon my bias phrasing.
[-z-] asked: do you think distributing warsow as one package is legal under the licensing terms?
crizis answers: Yes, it is. Even Richard Stallman himself blessed way of having open engine and restricted artwork. All code in Warsow is open source, artwork is not.
I found this interesting and with some conversation with with fellow Xonoticans, I came to learn how Richard Stallman, the founder of free software, feels about art in FOSS and I couldn’t disagree more. How is requiring the source for compiled programs any different than requiring the source for art?
Expanding On My Feelings
In my opinion, non-free art in free software is not in good spirit, it does not help others learn and it can hurt the growth of the game. The distinction between art and code gets further blurred when you see how interactive the artwork is.
I can argue that maps are code. They are a meta file, you can open them up in your text editor and edit them, they are filled with coordinates of brushes and entities, that hold keys with settings for the objects references to textures and can even contain some mild programming. Shader files are used to enhance textures and brushes. It’s not conventional programming, it’s closer to “virtual circuitry” as MrBougo called it.
This information is lost if source is not provided. Mappers have two choices on how to de-construct such features. Reverse engineer or decompile the map. The former likely being a waste of someone’s time and the later being an example of two wrongs not making it right.
I do not mean this as an attack on Warsow, it was only what re-lit my interest in the topic and the views I found by RMS were shocking. I think this should be a topic for discussion because in my eyes, art should fall under a similar license as code in FOSS, especially in software such as a video game where media is more advanced and interactive.
MySQL and Python – The Problems and [Some] Solutions
Oct 15th
Intro
I’m still relatively new to Python. I dabble once in a while. Usually when I catch myself writing something overly complicated in bash. I figured doing MySQL from a Python script would be easier and better implemented in Python. Well, I was in for a few surprises I’d like to share with others looking to integrate with MySQL in Python before you encounter the same problems I did.
Getting on with it
As a Python noob, it made sense to me to use the python-mysqldb module. It “works” but not well. Read through the [working] code below and see if you can find the problem and how I circumvented it.
#!/bin/python
# Tyler Mulligan (tyler@doknowevil.net)
# MySQL the WRONG way in Python
import MySQLdb
def connection_settings():
global DB_ADMIN, DB_ADMIN_PASSWORD, DB_NAME, DB_HOST, DB_USER, DB_PASSWORD
DB_ADMIN="root"
DB_ADMIN_PASSWORD="local"
DB_NAME="foobardb"
DB_HOST="localhost"
DB_USER="foobar"
DB_PASSWORD="local"
def run_admin_sql():
conn = MySQLdb.Connection(host=DB_HOST, user=DB_ADMIN, passwd=DB_ADMIN_PASSWORD)
cursor = conn.cursor()
#cursor.execute("DROP USER %s@%s", (DB_USER, DB_HOST))
#cursor.execute("DROP DATABASE %s" % DB_NAME)
cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (DB_USER, DB_HOST, DB_PASSWORD))
cursor.execute("CREATE DATABASE %s" % DB_NAME)
cursor.execute("GRANT USAGE ON %s.* TO %s@%s IDENTIFIED BY '%s'" % (DB_NAME, DB_USER, DB_HOST, DB_PASSWORD))
cursor.execute("GRANT ALL PRIVILEGES ON *.* to %s@%s IDENTIFIED BY %s", (DB_USER, DB_HOST, DB_PASSWORD))
cursor.close()
conn.close()
conn = MySQLdb.Connection(db=DB_NAME, host=DB_HOST, user=DB_USER, passwd=DB_PASSWORD)
cursor = conn.cursor()
cat_table_sql = """CREATE TABLE cats
(
`id` int(3) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`age` int(2) NOT NULL,
`type` int(2) NOT NULL,
PRIMARY KEY (`id`)
)"""
cursor.execute(cat_table_sql)
cursor.execute("INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)", ("fluffy", 5, 1))
cursor.execute("INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)", ("meow meow", 6, 1))
cursor.execute("INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)", ("purrfect", 3, 1))
cursor.execute("SELECT * FROM cats")
results = cursor.fetchall()
cursor.close()
conn.close()
return results
connection_settings()
print run_admin_sql()The problem is parameterization. The python-mysqldb module sucks at it. It’s glaringly obvious when you look at the follow snippet and how I worked around it.
cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (DB_USER, DB_HOST, DB_PASSWORD)) # GOOD
cursor.execute("CREATE DATABASE %s" % DB_NAME) # BAD NEWS BEARS
cursor.execute("CREATE DATABASE %s", (DB_NAME)) # but the module won't support this
The difference, is that the first implementation uses the module’s parameterization to escape the variables that are passed to it, making it safe. The second is using Python’s string formatter which means I’d have to do all the escaping and sanitization prior, which is obviously more dangerous and annoying.
The MySQLdb docs bury this little note, “Parameter placeholders can only be used to insert column values. They can not be used for other parts of SQL, such as table names, statements, etc.”
You can implement it this way but you’ll be wasting your time. There are better modules out there to make up for this one’s shortcomings. OurSQL and SQLAlchemy were the two libraries recommended to me in #python on irc.freenode.org. I will make another post when I develop the same example above using one of these libraries.




