Monday, February 9, 2009

WTF Nokia? N810 and E71 Won't Charge from USB?

This is completely retarded. It almost makes them unusable. Even worse, the frakin charger is is 5v... I'm half tempted to tear the devices open and put a trace wire from the usb connector to the charger connector so it will automatically charge. I like being able to use my laptop as a backup battery for my other devices. I like being able to use one cord to charge any device. I like being able to carry a small generic cord that I can plug in to the front of any computer rather than a large charger that I have to dig under the desk to plug in...

It doesn't matter how awesome your device is, but you can really piss people off if you do something stupid like this. On that note, why the hell doesn't the iPhone support A2DP (or HID, or USB Mass Storage, or SD...)?


Ugh.

Forms: FDF, PDF, and PHP

I have always been somewhat opposed to PDF documents. While they are great for cross-platform viewing and printing, the inability to edit them without buying special software was philosophically unacceptable. Also, not being able to save forms you fill out is really stupid. While there are some free alternatives now, they are really a kind of pain in the ass compared to Adobe Professional. So, unfortunately, that is what I used to get this to work quickly and easily. Thanks to Justin Koivisto, who's tutorial really helped.

For those of you that don't know (as I didn't before starting this project), FDF files are used to save filled out PDF forms, however they don't store the original PDF document. Instead the FDF file just has a pointer to the PDF document which can either be on the local computer or on the web.

So here is the scenario:

1) User fills out an online form.
2) PHP parses the form, and creates a VCard as well as an FDF.
3) PHP emails the files as attachments, and displays the filled out PDF for the user to print.

This is very useful for populating PDF forms that already exist, and may be in use in paper form. This makes it easy to transition to an electronic system.


The first step is a standard HTML form that will submit the data to a PHP script (application.html):

<html>
<body>
<form method="post" action="./submit.php">
<table>
<tr><td>First Name</td><td><input type="text" name="firstName" /></td></tr>
<tr><td>Last Name</td><td><input type="text" name="lastName" /></td></tr>
<tr><td>Mobile Phone Number</td><td><input type="text" name="mobilePhone" /></td></tr>
<tr><td>Home Phone Number</td><td><input type="text" name="homePhone" /></td></tr>
<tr><td>E-Mail</td><td><input type="text" name="email" /></td></tr>
<tr><td>Date of Birth (MM-DD-YYYY)</td><td><input type="text" name="dobMonth" maxlength="2" size="2"/>-<input type="text" name="dobDay" maxlength="2" size="2"/>-<input type="text" name="dobYear" maxlength="4" size="4"/></td></tr>
<tr><td>Address</td><td><input type="text" name="address" /></td></tr>
<tr><td>City</td><td><input type="text" name="city" /></td></tr>
<tr><td>State</td><td><input type="text" name="state" /></td></tr>
<tr><td>Zip Code</td><td><input type="text" name="zip" /></td></tr>
<!--<tr><td></td><td><input type="text" name="" /></td></tr>-->
<tr><td>Age</td><td><input type="text" name="age" /></td></tr>
</table>
<input type="submit" value="Submit" />
</form>
</body>
</html>



Next is the PHP script to create the VCard and FDF, emails them, and displays the FDF (submit.php):

<?php

include("./vcard.php");
include("./fdf.php");
include ("./mail_attachment.php");

$emailto = "someone@example.com";

//The pdf file that the fdf file points to:
$pdf_doc='http://example.com/application.pdf';


//We need to check POST variables to make sure the form was submitted correctly, we should also make sure they don't enter more than one email address, and that they enter an email address
/*
if(isset($_POST["firstName"])) {
echo $_POST["firstName"];
}
else
echo "BAD!!!!";
*/
$v = new vCard();

$v->setPhoneNumber($_POST["mobilePhone"], "PREF;CELL;VOICE");
$v->setPhoneNumber($_POST["homePhone"], "PREF;HOME;VOICE");
$v->setName($_POST["lastName"], $_POST["firstName"], "", "");
$v->setBirthday($_POST["dobYear"]."-".$_POST["dobMonth"]."-".$_POST["dobDat"]);
$v->setAddress("", "", $_POST["address"], $_POST["city"], $_POST["state"], $_POST["zip"], "US");
$v->setEmail($_POST["email"]);
//$v->setNote("You can take some notes here.\r\nMultiple lines are supported via \\r\\n.");
//$v->setURL("http://www.thomas-mustermann.de", "WORK");
/*
$output = $v->getVCard();
$filename = $v->getFileName();

Header("Content-Disposition: attachment; filename=$filename");
Header("Content-Length: ".strlen($output));
Header("Connection: close");
Header("Content-Type: text/x-vCard; name=$filename");

echo $output;*/

/*$outfdf = fdf_create();
fdf_set_value($outfdf, "volume", $volume, 0);

fdf_set_file($outfdf, "http:/testfdf/resultlabel.pdf");
fdf_save($outfdf, "outtest.fdf");
fdf_close($outfdf);
Header("Content-type: application/vnd.fdf");
$fp = fopen("outtest.fdf", "r");
fpassthru($fp);
unlink("outtest.fdf");*/

foreach($_POST as $name => $val) {
$data[$name] = $val;
//echo $name."<br/>";
}


// generate the file content
$fdf_data=createFDF($pdf_doc,$data);
$attachments[0]['data']=$v->getVCard();
$attachments[0]['filename']=$_POST['firstName'].$_POST['lastName'].".vcf";
$attachments[0]['mime']="text/x-vcard";

$attachments[1]['data']=$fdf_data;
$attachments[1]['filename']=$_POST['firstName'].$_POST['lastName'].".fdf";
$attachments[1]['mime']="application/vnd.fdf";

$from=$_POST['firstName']." ".$_POST['lastName']." <".$_POST['email'].">";

mail_attachment($from,$emailto,"Rental Application", "Lease: from ".$_POST['leaseStart']." to ".$_POST['leaseEnd'], $attachments);
Header("Content-type: application/vnd.fdf");
echo $fdf_data;

?>

This shows an example of how to use the multi-attachment email script shown below. We should be checking the POST inputs to make sure someone isn't trying to do something nasty, there could be a security problem there.


Notably, there included files that you need. The first is the VCard creator (vcard.php):

<?

/***************************************************************************



PHP vCard class v2.0

(c) Kai Blankenhorn

www.bitfolge.de/en

kaib@bitfolge.de





This program is free software; you can redistribute it and/or

modify it under the terms of the GNU General Public License

as published by the Free Software Foundation; either version 2

of the License, or (at your option) any later version.



This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.



You should have received a copy of the GNU General Public License

along with this program; if not, write to the Free Software

Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.



***************************************************************************/





function encode($string) {

return escape(quoted_printable_encode($string));

}



function escape($string) {

return str_replace(";","\;",$string);

}



// taken from PHP documentation comments

function quoted_printable_encode($input, $line_max = 76) {

$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');

$lines = preg_split("/(?:\r\n|\r|\n)/", $input);

$eol = "\r\n";

$linebreak = "=0D=0A";

$escape = "=";

$output = "";



for ($j=0;$j<count($lines);$j++) {

$line = $lines[$j];

$linlen = strlen($line);

$newline = "";

for($i = 0; $i < $linlen; $i++) {

$c = substr($line, $i, 1);

$dec = ord($c);

if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only

$c = "=20";

} elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required

$h2 = floor($dec/16); $h1 = floor($dec%16);

$c = $escape.$hex["$h2"].$hex["$h1"];

}

if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted

$output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay

$newline = " ";

}

$newline .= $c;

} // end of for

$output .= $newline;

if ($j<count($lines)-1) $output .= $linebreak;

}

return trim($output);

}



class vCard {

var $properties;

var $filename;



function setPhoneNumber($number, $type="") {

// type may be PREF | WORK | HOME | VOICE | FAX | MSG | CELL | PAGER | BBS | CAR | MODEM | ISDN | VIDEO or any senseful combination, e.g. "PREF;WORK;VOICE"

$key = "TEL";

if ($type!="") $key .= ";".$type;

$key.= ";ENCODING=QUOTED-PRINTABLE";

$this->properties[$key] = quoted_printable_encode($number);

}



// UNTESTED !!!

function setPhoto($type, $photo) { // $type = "GIF" | "JPEG"

$this->properties["PHOTO;TYPE=$type;ENCODING=BASE64"] = base64_encode($photo);

}



function setFormattedName($name) {

$this->properties["FN"] = quoted_printable_encode($name);

}



function setName($family="", $first="", $additional="", $prefix="", $suffix="") {

$this->properties["N"] = "$family;$first;$additional;$prefix;$suffix";

$this->filename = "$first%20$family.vcf";

if ($this->properties["FN"]=="") $this->setFormattedName(trim("$prefix $first $additional $family $suffix"));

}



function setBirthday($date) { // $date format is YYYY-MM-DD

$this->properties["BDAY"] = $date;

}



function setAddress($postoffice="", $extended="", $street="", $city="", $region="", $zip="", $country="", $type="HOME;POSTAL") {

// $type may be DOM | INTL | POSTAL | PARCEL | HOME | WORK or any combination of these: e.g. "WORK;PARCEL;POSTAL"

$key = "ADR";

if ($type!="") $key.= ";$type";

$key.= ";ENCODING=QUOTED-PRINTABLE";

$this->properties[$key] = encode($name).";".encode($extended).";".encode($street).";".encode($city).";".encode($region).";".encode($zip).";".encode($country);



if ($this->properties["LABEL;$type;ENCODING=QUOTED-PRINTABLE"] == "") {

//$this->setLabel($postoffice, $extended, $street, $city, $region, $zip, $country, $type);

}

}



function setLabel($postoffice="", $extended="", $street="", $city="", $region="", $zip="", $country="", $type="HOME;POSTAL") {

$label = "";

if ($postoffice!="") $label.= "$postoffice\r\n";

if ($extended!="") $label.= "$extended\r\n";

if ($street!="") $label.= "$street\r\n";

if ($zip!="") $label.= "$zip ";

if ($city!="") $label.= "$city\r\n";

if ($region!="") $label.= "$region\r\n";

if ($country!="") $country.= "$country\r\n";



$this->properties["LABEL;$type;ENCODING=QUOTED-PRINTABLE"] = quoted_printable_encode($label);

}



function setEmail($address) {

$this->properties["EMAIL;INTERNET"] = $address;

}



function setNote($note) {

$this->properties["NOTE;ENCODING=QUOTED-PRINTABLE"] = quoted_printable_encode($note);

}



function setURL($url, $type="") {

// $type may be WORK | HOME

$key = "URL";

if ($type!="") $key.= ";$type";

$this->properties[$key] = $url;

}



function getVCard() {

$text = "BEGIN:VCARD\r\n";

$text.= "VERSION:2.1\r\n";

foreach($this->properties as $key => $value) {

$text.= "$key:$value\r\n";

}

$text.= "REV:".date("Y-m-d")."T".date("H:i:s")."Z\r\n";

//$text.= "MAILER:PHP vCard class\r\n";

$text.= "END:VCARD\r\n";

return $text;

}



function getFileName() {

return $this->filename;

}

}





// USAGE EXAMPLE

/*

$v = new vCard();



$v->setPhoneNumber("+49 23 456789", "PREF;HOME;VOICE");

$v->setName("Mustermann", "Thomas", "", "Herr");

$v->setBirthday("1960-07-31");

$v->setAddress("", "", "Musterstrasse 20", "Musterstadt", "", "98765", "Deutschland");

$v->setEmail("thomas.mustermann@thomas-mustermann.de");

$v->setNote("You can take some notes here.\r\nMultiple lines are supported via \\r\\n.");

$v->setURL("http://www.thomas-mustermann.de", "WORK");



$output = $v->getVCard();

$filename = $v->getFileName();



Header("Content-Disposition: attachment; filename=$filename");

Header("Content-Length: ".strlen($output));

Header("Connection: close");

Header("Content-Type: text/x-vCard; name=$filename");



echo $output;*/

?>


Next is the FDF creator (fdf.php):

<?php

/*

KOIVI HTML Form to FDF Parser for PHP (C) 2004 Justin Koivisto

Version 2.1.2

Last Modified: 9/12/2005



This library is free software; you can redistribute it and/or modify it

under the terms of the GNU Lesser General Public License as published by

the Free Software Foundation; either version 2.1 of the License, or (at

your option) any later version.



This library is distributed in the hope that it will be useful, but

WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public

License for more details.



You should have received a copy of the GNU Lesser General Public License

along with this library; if not, write to the Free Software Foundation,

Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA



Full license agreement notice can be found in the LICENSE file contained

within this distribution package.



Justin Koivisto

justin.koivisto@gmail.com

http://koivi.com

*/



/*

* createFDF

*

* Takes values submitted via an HTML form and fills in the corresponding

* fields into an FDF file for use with a PDF file with form fields.

*

* @param $file The pdf file that this form is meant for. Can be either

* a url or a file path.

* @param $info The submitted values in key/value pairs. (eg. $_POST)

* @result Returns the FDF file contents for further processing.

*/

function createFDF($file,$info){

$data="%FDF-1.2\n%????\n1 0 obj\n<< \n/FDF << /Fields [ ";

foreach($info as $field => $val){

if(is_array($val)){

$data.='<</T('.$field.')/V[';

foreach($val as $opt)

$data.='('.trim($opt).')';

$data.=']>>';

}else{

$data.='<</T('.$field.')/V('.trim($val).')>>';

}

}

$data.="] \n/F (".$file.") /ID [ <".md5(time()).">\n] >>".

" \n>> \nendobj\ntrailer\n".

"<<\n/Root 1 0 R \n\n>>\n%%EOF\n";

return $data;

}

?>

There is an official PHP FDF creator, but it uses some ridiculous dll file that you need to install. PHP is great at string manipulation, why the heck do we need a dll? Anyway, thanks a lot Justin Koivisto.

Finally a custom email script I wrote to email multiple attachments (mail_attachment.php):

<?php

function mail_attachment ($from , $to, $subject, $message, $attachments){

$email_from = $from; // Who the email is from

$email_subject = $subject; // The Subject of the email

$email_txt = $message; // Message that the email has in it



$email_to = $to; // Who the email is to

$headers = "From: ".$email_from;


$semi_rand = md5(time());

$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";



$headers .= "\nMIME-Version: 1.0\n" .

"Content-Type: multipart/mixed;\n" .

" boundary=\"{$mime_boundary}\"";



$email_message .= "This is a multi-part message in MIME format.\n\n" .

"--{$mime_boundary}\n" .

"Content-Type:text/html; charset=\"iso-8859-1\"\n" .

"Content-Transfer-Encoding: 7bit\n\n" . $email_txt . "\n\n";



foreach ($attachments as $a) {

$data = chunk_split(base64_encode($a['data']));



$email_message .= "--{$mime_boundary}\n" .

"Content-Type: {$a['mime']};\n" .

" name=\"{$a['filename']}\"\n" .

"Content-Transfer-Encoding: base64\n\n" .

$data . "\n\n";

}



$email_message .= "--{$mime_boundary}--\n";



$ok = @mail($email_to, $email_subject, $email_message, $headers);



if($ok) {

} else {

die("There was a problem sending the email. Please check your inputs.");

}

}



?>



Thank you about.com for the HTML Converter.