Gmail headers, blank message, empty emails, and frustration with PHP mail
Turns out it isn't PHP's fault at all - as usual.
Several people have had the issue of Gmail showing blank or empty messages through its web interface, but not when you use SMTP or IMAP to download the messages and view them in thunderbird/outlook. PHP emailing is tricky, but not difficult... It isn't the fault of the language - its our fault as programmers for not jumping right into reading RFCs for email.
Gmail is simply put, very picky about Content-Type: multipart/alternative;
Here's a checlist of things you can look for...
- Remove all carriage returns (\r) from the email's headers and body. Use the standard newline (\n) instead of the windows fluff.
- Ensure your content-encoding and charset are set to iso-8859-1 and 8bit
- Ensure your content-type are either text/plain or text/html
- Double check your BOUNDARY! This was my problem - everyone knows that boundaries must start with --, but the FINAL boundary must also END with --.
Linksys SRW224P Password Reset and Console Issues
The reason I started this blog was so I could remember things that I'd probably forget. Today I came across something that needs to be blogged, simply because there is NO good information out there.
Say you have a linksys SRW224P, and that you don't know the admin password.
Well, there's no reset button, and your web interface will just keep asking for the info you don't have... So you're going to have to do this the complicated way.
The console.
Here's the deal - USE THE LINKSYS CABLE. PERIOD. I saw a post on the linksys forums regarding the pinout for the cable they provide - I don't know if its WRONG or what - but a straight-through cable WILL NOT WORK. I know this, because I went to RadioShack, blew $20 on a cable, and it didn't work. Null Modem, or Straight through - no dice.
Once you have the cable - connect at 38400, 8 bits, No Pairity, 1 stop bit. You'll see the message "please press ENTER to start session".
Reboot the unit by unplugging it, and replugging it. HOLD CTRL+U IN YOUR SESSION. This will bring up a diagnostics menu. Delete the file "startup-config" and reboot the machine. It will take a few minutes - but it will ask you for a login. Username: admin - Password: [blank]
Ta-da. Now upgrade your firmware because this unit has had a ton of issues... 2.0.2.2 is the final version.
IE6 double-margin float bug
IE6 doubles the margin on floated elements. The fix? Add display: inline; - I hate IE6.
Internet Explorer-isms
The culmination of several minutes of head bashing came to conclusion.
I contract to various companies... one such company has a codebase that's been through several programmers. A certain part of this software has a single page with multiple form fields, but no actual FORM element in the XHTML. Obviously, the forms are submitted using Asynchronous HTTP request - AJAX. (But I don't say AJAX since there's no XML involved)
To get on with things - It was requested that since one of these forms is actually a LOGIN form.... (save me the comments about how logins via Asynchronous HTTP are insecure - I'm aware... I just do as I'm told.) ...the client would like pressing enter to submit the login. Usability wise its a great decision.
Herein lies the problem. I attach an OnKeyPress event to the form's password object. It calls a function to see if the enter key was pressed, and if so - it sends the form contents on using the existing "sendOut" method.
The "sendOut" method has two functions though - since there are two sets of fields. The simple way to tell it which to use is by passing a variable - a string of either 'returning' or 'newreg'. Returning, means process the registration information --- Newreg, means to call the new registration script.
This is no difficult task - I simply attach the onKeyPress="sendOut("returning");" method.
Tested - works great. Two weeks go by. For some reason - there are TONS of blank registrations popping up in the database. (Which is another story.) We get to looking, and its caused when we log in! What could be happening here?
I start entering debug code... First a prompt that alerts every time the sendout method is called. It shows twice on pressing enter.... odd... I scan the code - no dice for a second call. Now I specifically say to alert the TYPE of sendout that's being called...
...newreg... ...returning...
Now this is weird. I completely remove the new registration calls except for the click method.
...newreg... ...returning...
WTF? At this point - I note that Firefox works fine, and IE has the problem... then I start getting the idea of what's going on.
You see, Internet Explorer thinks its smarter than most programmers - and actually 'invents' its own HTML code to correct standardization issues within the browser, and to a degree to fix non-compliant code. The solution ended up working its way out in an AIM conversation with my Flash employee - Dorian. The final line, for some reason, made me want to strangle whoever wrote IE 7.
(04:32:53 PM) LAMP - Dorian: What was the solution
(04:33:18 PM) JStarkeyCIT: IE probably thinks it knows best and puts an imaginary form element around those fields
(04:33:39 PM) JStarkeyCIT: when you press enter - it tries to submit but doesn't find a button, so it used the first <input type="image"> it could find
(04:33:55 PM) LAMP - Dorian: makes sense
(04:34:04 PM) JStarkeyCIT: I changed the <input type="image" to just a regular image, since we're not using it like a form elemement anyway
(04:34:32 PM) JStarkeyCIT: so now when it calls the fake submit to the non-existant form, it cant find anything and gives up
(04:34:35 PM) JStarkeyCIT: (peacefully)
Yes, a fake submit to a non-existant form. IE assumed two things - that combined caused bizzarre behavior. Pressing enter was handled correctly - however IE assumed that a <FORM> element was necessary around ALLLLLLL the input elements. Since my method returns true - it figures that IT should handle the key press as an attempt to submit the non-existant form. Since a handler obviously doesn't exist, it tries to find the next best thing... an <input type="image">. The first one in the non-existant form.
There you have it. Rant Over.
Virtual Box and Your Kernel
My VirtualBox installation has been locking up lately when I try to launch Windows XP. It always hangs at a window saying "Spawning Session 0%"...
NOTE: If you ever upgrade your kernel - YOU NEED TO RECOMPILE YOUR KERNEL VIRTUALIZATION MODULES!
Its easy, thank goodness...
sudo /etc/init.d/vboxdrv setup
EDIT: On a wiser note - Ubuntu users should install dkms via apt-get to automatically do this.
JVC Camcorder with Ubuntu - Also a bit on media in ubuntu
First of all - I just discovered the Medibuntu repository - which has a TON of extra support in the avcodec area... everyone who has ubuntu should follow THIS GUY's advice and add the repository using these two commands....
sudo wget http://www.medibuntu.org/sources.list.d/hardy.list -O /etc/apt/sources.list.d/medibuntu.list
wget -q http://packages.medibuntu.org/medibuntu-key.gpg -O - | sudo apt-key add - && sudo apt-get update
Now that being said - here's my situation. Right before getting extremely tired of Windows I bought a JVC GZ-MG130U at firesale price from BestBuy courtesy of a price match at Wal-Mart. Great little camcorder.
The camera is great, but it records to its internal harddisk in some 'MOD' format - Which is apparently a container codec for MPEG2 video and AC3 audio. Well, that doesn't exactly store well or play well much of anywhere. It DOES play after I download several codecs - and ONLY in mplayer, even VLC can't figure out what kind of video it is!
Well, I think MPEG4 would be great - and there is an open source implementation called XVID - so I'll just use transcode to fix it. Here's a script that I wrote that helps convert these things quickly. "convt.sh"
You need to apt-get install the "transcode" package for this to work.
#!/bin/bash echo $1 | sed s/'MOD'/'AVI'/ | xargs transcode -i $1 -y xvid -Z 720x480 -o
As a note - the transition from 4:3 to 16:9 sucks.
The script is (as usual) ghetto fabulous. It spits the filename (param1) into sed, which replaces MOD with AVI, and then pipes that as the output of an xarg'd transcode with the original filename (param1) as the input file. I've got it hooked up with a batch conversion script below.
#!/bin/bash for i in *.MOD; do ./convt.sh $i; done; v=`date +%y-%m-%d_%H:%M` mkdir $v mv *.AVI ./$v/ rm *.MOD
The script runs the original "convt.sh" on all the MOD files in the local directory, then moves all the resulting AVI files into a new folder - named after the time the script was ran. It then deletes all the other files.
The really efficient way to do this would be to add the RM to the original script so you don't end up doubling the number of videos on disk at one point. Instead of 2N storage space, you'd be left with N+1 for a brief instant, then back to N. Anyhow...
Time to go eat. More later on video converting and making a script to convert these to FLV when I upload them.
Ghettofabulous modifications for TinyMCE - uploading images the REAL easy way
I googled for 30 minutes today and was SHOCKED to find that no one had copy-paste code available that modified TinyMCE to accept uploaded images. Well, I found lots of code that did exactly what I was after, but it was all bloat. I've noticed a tendency for programmers to avoid doing things the easy way in favor of doing things the 'cool' way. Now there's an eternal struggle here between time involved, code maintainability, and robustness.
As all programmers, I have somewhat of an ego - even though I would say I am no expert. This code is the REAL easy way to modify TinyMCE to accept image uploads. There are some steps I will list beyond what is required, you may ignore them. The general idea is that once a picture is uploaded, you COULD just tell a user to copy and paste the image URL from one area to another in the same window - explained later - but my method automatically moves the src over. This code uses a PHP backend, but the METHOD works in any language. Its rudimentary.
This is several steps, but all of them are very basic.
- Download and unzip TinyMCE. I started by taking the 'advanced' example and modifying it.
- Take the tiny_mce folder and copy it to your web server. As is.
- Copy the TinyMCE.init method from the example file, and modify it to your liking. I simply rearranged buttons, and removed some bloat. Sample code below...
<script type="text/javascript" src="<?= $base_url ?>/js/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
plugins : "safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
// Theme options
theme_advanced_buttons1 : "styleselect,fontsizeselect,formatselect,bold,italic,underline,strikethrough,|,bullist,numlist,|,outdent,indent,blockquote,|,justifyleft,justifycenter,justifyright,justifyfull,|,link,unlink,anchor,image,|,forecolor,backcolor,|,iespell,media,advhr,|,nonbreaking,pagebreak",
theme_advanced_buttons2 : "template,styleprops,|,visualaid,visualchars,|,hr,|,cut,copy,paste,pastetext,pasteword,|,undo,redo,|,search,replace,|,tablecontrols,|,code,cleanup,removeformat",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
// Example content CSS (should be your site CSS)
content_css : "<?= $base_url ?>/css/default.css",
});
</script>
<textarea name="text" id="text" rows="20"></textarea> - Save it. Check it out. Look good? Awesome.
- Open up /tiny_mce/plugins/advimage/image.html in your favorite editor. This is the page that tinymce calls as a template for the image editing button. This is where we'd like to upload our images, because users know the button with the picture means put a picture on the page.
- Around line 50 on the normal image.htm you'll see some table-rows (FOR SHAME TINY MCE!) that are used to line things up. There isn't any text that you'll recognize because TinyMCE pulls its language from another file, just incase someone who doesn't speak english wants to use the plugin. We are going to add another row with an IFRAME in it. Why an IFRAME? Because its an easy way to embed a separate form in the middle of an existing one without BORKING what already works. My modified code is below...
<tr>
<td><label for="src_list">{#advimage_dlg.image_list}</label></td>
<td><select id="src_list" name="src_list" onchange="document.getElementById('src'). [ TRIMMED FOR LENGTH ]
</tr>
SNIP HERE! -----------------------------------------------
<tr>
<td class="column1"><label id="titlelabel" for="title">{#advimage_dlg.fsrc}</label></td>
<td colspan="2"><iframe src="upload.htm" style="height: 24px; width: 300px;" scrolling="no" frameborder="0"></iframe></td>
</tr>
ABOVE IS WHAT I ADDED ------------------------------
<tr>
<td class="column1"><label id="altlabel" for="alt">{#advimage_dlg.alt}</label></td>
<td colspan="2"><input id="alt" name="alt" type="text" value="" /></td>
</tr> - That's all to adding the box.... Now we need to add the actual file uploading FORM in upload.html - which is the SRC listed for the iframe.
- Open a new file in your favorite editor and save it in the SAME tinymce/plugins/advimage/ folder as "upload.htm". All you're doing is making a quick and dirty form to handle the upload. NOTE: This is where I went slightly above and beyond and it wasn't required! Instead of having a submit button, I simply wanted the control to GO as soon as the image was selected. I added some funky javascript using a Timeout Function because OnChange has issues for security reasons. Here is the code I used... There is a lot wrong with it programmatically. (style and javascript in the head)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
body { margin: 0px; padding:0px; }
input { border: solid black 1px; }
</style>
<!-- Unnecessary if you just add a submit button -->
<script type="text/javascript">
function go() {
if(document.getElementById('upload').value != ''){
alert('ho');
document.getElementById('uploadform').submit();
} else {
setTimeout('go()',1000);
}
}
window.onload = go;
</script>
<!-- Unnecessary if you just add a submit button -->
</head>
<body>
<form action="uploader.php" method="post" id="uploadform" enctype="multipart/form-data">
<input type="file" name="upload" id="upload" />
<!-- add a submit button here if you want to make it easy -->
</form>
</body>
</html> - Save. You should now be able to clear your cache and refresh your page using the tinyMCE editor and see the box. Now we add the handler. Your handler can do whatever you like... mine is only moderately fancy. A *SIMPLE* upload form would do one of two things, spit out an error message when there is a problem, or return the URL that a user can copy/paste into the SRC field right above it. AGAIN I WENT A STEP BEYOND THE BASICS - I set mine up so that when the image is uploaded, it generates a URL for the picture, then reloads the PARENT frame (the actual image form) and sets the SRC by passing it as a parameter. Here's my code BUILT FOR MY FRAMEWORK... I have whittled it down so you get the idea and can make it work on your own. Note how in the previous code I set my form action to "uploader.php" - that's the file we'll be making.
<?
if (!is_uploaded_file($_FILES['upload']['tmp_name'])) {
echo "problem!";
} else {
//do your business here with "move_uploaded_file"...
//This is where you could just spit out a URL for your image, my code sends out a page that causes the parent frame to reload as described above
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
body { margin: 0px; padding:0px; }
input { border: solid black 1px; }
</style>
<script type="text/javascript">
function go() {
//this "change_parent_url" bit will be addressed in a sec, all that matters is that you set your image URL in the src= parameter
// note how this is image.php instead of image.htm ? My server only runs php code on .php files. Step 11 explains how to
// modify TinyMCE so changing the filename won't screw things up. Its really easy.
parent.change_parent_url('image.php?src=YOUR_IMAGE_URL');
}
window.onload = setTimeout('go()',1000);
</script>
</head>
<body>
Adding image...
</body>
</html>
<?
}
?> - Ok - to review, we've got the image tool modified, the form created, and the backend up. Now I just need to finish going above and beyond by modifying the image.htm to now be my new image.php script - so the "change_parent_url" function is defined, and so my src is prepopulated. Again, this part is highly unnecessary doing this the simple way of making a user copy/paste the URL for the image. Insert the first snippet in the top of [what is now still] image.htm , and then modify your script to match the second snippet - which prefills the SRC.
<script type="text/javascript">
function change_parent_url(url)
{
document.location=url;
}
</script>
----- This code is normally around line 35 - note that all I did is put a simple PHP injection into the value="" attribute.
<tr>
<td class="column1"><label id="srclabel" for="src">{#advimage_dlg.src}</label></td>
<td colspan="2"><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input name="src" type="text" id="src" value="<?= $_GET['src'] ?>" class="mceFocus" onchange="ImageDialog.showPreviewImage(this.value);" /></td>
<td id="srcbrowsercontainer"> </td>
</tr>
</table></td>
</tr> - OK! Now we're all done modifying that file, and want to save it as image.php so the php code will process. BUT WAIT - Zomg TINYMCE WILL STILL BE LOOKING FOR IMAGE.HTM! WHAT EVER SHALL I DO? This was the easiest part. Modify
/tinymce/plugins/advimage/editor_plugin.js ---- do a search replace on "image.htm" and put in "image.php". It should hit once. Save. YOU ARE DONE! HOORAY!
Again, this is not the PERFECT way to do this - but I wanted something that was quick and dirty and I managed this in about 30 minutes of hacking around. Enjoy!
Also - I leave you with this quick thought - color safe bleach is a JOKE! The idea that bleach doesn't change colors should tell you something about what you're trying to do. "Well I want THIS color to come out, but not THAT one!" This capability only exists with borg nanoprobes - and voodoo magic.
"When your tools become part of the problem, you aren't heading in the right direction."
Inefficient Image Resizing with PHP
This code is absolute CRAP, that is your warning! I had a bug in my logic today involving a resizing algorithm that automatically crops images. The example (working) is below...
The problem lies in that sometimes you don't know how an image will be resized, but you want to maintain some semblance of an aspect ratio so the image isn't "squished". This means that when width and height are both specified and the aspect ratio (width / height) is different, the image will be either "short and fat" or "tall and skinny". [aspect ratio is either bigger or smaller than the original]. If the image is short and fat, then you'll want to trim some off of the bottom --- if the opposite, you'll want to trim some off of the side.
Well, its trivial - but for some reason my brain wasn't engaged today - so I figured I'd offer up my code so people can steal it.
This is the original image - notice how the pie is round.
This image I specified a smaller height - and you can see that instead of squishing the image, it was cropped.
This image was taller and skinnier, so the resizing happened as well as some cropping on the x axis.
Anyway ---- All of this so I could steal a funny picture from Digg. Crap code follows - it should be optimized by calling ImageSX and ImageSY once only.... Enjoy low hanging fruit. :) This code works on top of my company's proprietary web development framework as a standalone script. I added comments to help you. I was originally doing this using the absolute aspect ratio... its logically easier to understand when you use two "resize ratio" variables.
<?
require_once('../inc/config.php'); //delete this if you aren't using Element
$pic = new Picture($_GET['id']); //do your own SQL here
if($pic->getID()){ //your own method for making sure the picture is valid
$src_img=ImageCreateFromJPEG($pic->getField('localfile')); //replace the ImageCreate param with your own image file
} else {
$src_img=ImageCreateFromJPEG($base_path.'upload/jpg/noimage.jpg'); //your default image
}
$src_aspect = ImageSX($src_img) / ImageSY($src_img);
$_GET['width'] = intval($_GET['width']);
$_GET['height'] = intval($_GET['height']);
if(!isset($_GET['width'])){
$_GET['width'] = 800;
}
if(!isset($_GET['height'])){
$_GET['height'] = (float)ImageSY($src_img) * ((float)$_GET['width']/(float)ImageSX($src_img));
}
if(isset($_GET['width']) && isset($_GET['height'])){
$dst_aspect = $_GET['width'] / $_GET['height'];
$rsz_y = $_GET['height'] / ImageSY($src_img);
$rsz_x = $_GET['width'] / ImageSX($src_img);
if($dst_aspect >= $src_aspect){
//image is wider than original
//get whole width
$crop_width = ImageSX($src_img);
//trim from bottom
$crop_height = $_GET['height'] * (1/$rsz_x);
} else {
//image is taller than original
//get whole height
$crop_height = ImageSY($src_img);
//trim from right
$crop_width = $_GET['width'] * (1/$rsz_y);
}
//at this point you know your destination bounds, source bounds, and they've been cropped if necessary
}
$dst_img=ImageCreateTrueColor($_GET['width'],$_GET['height']);
ImageCopyResampled($dst_img,$src_img,0,0,0,0,$_GET['width'],$_GET['height'],$crop_width,$crop_height);
ob_start('ob_gzhandler'); //compress the image because if its huge, load time sucks.
Header("Content-type: image/jpeg");
ImageJPEG($dst_img,'',100);
ob_end_flush();
//free the memory used for the images
ImageDestroy($src_img);
ImageDestroy($dst_img);
?>
Linux Audio Commands
This blog was started mainly because I keep finding all these linux commands and want to note them somewhere... if you found this and these help you out - or you find me entertaining - I welcome your feedback!
On Ubuntu 8.04 with the mplayer and lame packages, you can decompress just about anything (WMA, MP3, MP4, OGG, FLAC, etc) - and throw it into a nice tidy MP3 file at convenience.
To uncomopress an audio file into a wav....
mplayer -vo null -vc dummy -af resample=44100 -ao pcm:waveheader [INPUT FILENAME]
My understanding is that the -vo and -vc options specify the video-out and video-codec options since mplayer is actually designed for video, which are irrelevant to audio. -af is an "audio format" flag - resample=44100 resamples the audio to a standard bitrate (44100 = cd quality) - ao = "audio out" , pcm:waveheader means to format to a Pulse Controlled Modulation with a wavefile header.
Then again, I may be wrong on all of this. :) That's just how I understand it. I will say that it sucks getting a standard BS 'audiodump.wav' file output. There's probably an option to name the output that I missed.
The command to compress to MP3 is...
lame -m j -h --vbr-new -b 160 [INPUT FILE] -o [OUTPUT FILE]
LAME = LAME Ain't an MP3 Encoder, but it really is. OPTIONS: -m = mode, j means joint stereo, (Inspect this with [man lame] - some people don't like the quality), -h is a quality increasing options that isn't very well explained - its necessary for VBR (variable bit rate) encoding though.... -b is the bitrate setting, when used with --vbr-new, the new VBR algorithm it will set the average bitrate to 160 when compressing the file (slightly above CD quality). -o simply means output to file named.
Over and out.
Testing 123
This is a big fat freaking test.
