function smd_qr_code($atts, $thing=NULL) { extract(lAtts(array( 'type' => 'text', // text/link/bookmark/sms/phone/email/contact/geo/wifi 'data' => 'Hello world!', 'delim' => '|', 'format' => 'view', // view/download/raw 'width' => '200', 'height' => '200', 'quality' => 'L', // L/M/Q/H 'margin' => '4', 'bgcol' => '', 'alpha' => '', 'escape' => '', 'class' => '', 'html_id' => '', 'wraptag' => '', 'debug' => 0, ),$atts)); // Common regexes $re_url = '@^[http://|https://|ftp://].*@'; $re_email = "<^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$>"; $re_phone = '/^[0-9()\-+ ]+$/'; $re_msg = '/^.+$/'; $re_geo = '/^[0-9.\-]+$/'; $re_digits = '/^[0-9\+\-]+$/'; // Each entry links the 'type' attribute with an array of: // method name to call via $qrc->$method() // expected params array and their format regex //TODO: iappli ("app") $allowed_types = array( 'text' => array('text' => array('text' => $re_msg)), 'link' => array('link' => array('url' => $re_url)), 'bookmark' => array('bookmark' => array('title' => $re_msg, 'url' => $re_url)), 'sms' => array('sms' => array('phone' => $re_phone, 'text' => $re_msg)), 'phone' => array('phone_number' => array('phone' => $re_phone)), 'contact' => array('contact_info' => array('name' => $re_msg, 'address' => $re_msg, 'phone' => $re_phone, 'email' => $re_email)), 'email' => array('email' => array('email' => $re_email, 'subject' => $re_msg, 'message' => $re_msg)), 'geo' => array('geo' => array('lat' => $re_geo, 'lon' => $re_geo, 'height' => $re_digits)), 'wifi' => array('wifi' => array('type' => '^[WEP|WPA]$', 'ssid' => $re_msg, 'pass' => $re_msg)), ); if (array_key_exists($type, $allowed_types)) { $qrc = new smd_qrcode($width, $height, $quality, $margin, $bgcol, $alpha, $escape); $entry = $allowed_types[$type]; // Only ever one "entry" but it's the simplest way to split key=>value foreach ($entry as $method => $attribs) { $params = smd_qrcode_extract($attribs, $data, $delim, $method, $debug); } if ($params === false) { return ''; } else { // Run the function that prepares the data object $qrc->$method($params); } if ($format == 'view') { $tribs = ''; if (!$wraptag) { $tribs .= ($class) ? ' class="'.$class.'"' : ''; $tribs .= ($html_id) ? ' id="'.$html_id.'"' : ''; } $content = 'QR code'; return ($wraptag) ? doTag($content, $wraptag, $class, '', $html_id) : $content; } elseif ($format == 'download') { $file = $qrc->get_image(); $qrc->download_image($file); return ''; } elseif ($format == 'raw') { $content = $qrc->get_link(); return ($wraptag) ? doTag($content, $wraptag, $class, '', $html_id) : $content; } } else { trigger_error(smd_qr_code_gTxt('smd_qr_code_invalid_type', array('{type}' => $type)), E_USER_NOTICE); return ''; } } //------------------------ function smd_qrcode_extract($permitted, $data, $dlm, $tag, $debug=false) { $opts = do_list($data, $dlm); $out = array(); $count = 0; if ($debug) { echo '++ PERMITTED ITEMS / SUPPLIED ITEMS ++'; dmp($permitted, $opts); } if (count($permitted) != count($opts)) { trigger_error(smd_qr_code_gTxt('smd_qr_code_attribute_mismatch', array('{type}' => $tag, '{count}' => count($opts), '{expected}' => count($permitted))), E_USER_NOTICE); return false; } foreach ($permitted as $idx => $vars) { if (isset($opts[$count])) { $dataval = $opts[$count]; if (preg_match($vars, $dataval)) { $out[$idx] = $dataval; } else { trigger_error(smd_qr_code_gTxt('smd_qr_code_invalid_attribute', array('{attrib}' => $idx, '{tag}' => $tag)), E_USER_NOTICE); return false; } } else { // TODO: erm...? } $count++; } return $out; } function smd_qr_code_gTxt($what, $atts = array()) { $lang = array( 'smd_qr_code_attribute_mismatch' => "Number of parameters don't match in '{type}' QR code: given {count}, expecting {expected}", 'smd_qr_code_invalid_attribute' => "Invalid attribute '{attrib}' supplied in '{tag}' QR code. Check the format and order of data items", 'smd_qr_code_invalid_type' => "Invalid QR code type '{type}'", ); return strtr($lang[$what], $atts); } /************************************************************************************** * This script is developed by Arturs Sosins aka ar2rsawseen, http://code-snippets.co.cc * Feel free to distribute and modify code, but keep reference to its creator * * Class name prefixed with smd_ for use in Textpattern (to avoid namespace clashes) * Modified by Stef Dawson for Textpattern * * This class generate QR [Quick Response] codes with proper metadata for mobile phones * using google chart api http://chart.apis.google.com * Here are sources with free QR code reading software for mobile phones: * http://reader.kaywa.com/ * http://www.quickmark.com.tw/En/basic/download.asp * http://code.google.com/p/zxing/ * * For more information, examples and online documentation visit: * http://code-snippets.co.cc/PHP-classes/QR-code-generator-class ***************************************************************************************/ class smd_qrcode { private $api = 'http://chart.apis.google.com/chart'; private $data; private $dimensions = ''; private $quality = ''; private $colour = ''; private $escape = ''; // Constructor public function smd_qrcode($width, $height, $qual, $margin, $bgcol, $alpha, $esc) { $this->escape = $esc; // Build API strings $w = (is_numeric($width)) ? $width : 200; $h = (is_numeric($height)) ? $height : 200; $this->dimensions = $w.'x'.$h; $colours = array(); if ($alpha) $colours[] = 'a,s,000000'.substr($alpha, -2); if ($bgcol) $colours[] = 'bg,s,'.$bgcol; $this->colour = ($colours) ? join('|', $colours) : ''; $qual = strtoupper($qual); $szopts[] = ($qual && in_array($qual, array('L', 'M', 'Q', 'H'))) ? $qual : 'L'; if (is_numeric($margin)) $szopts[] = $margin; $this->quality = join('|', $szopts); } // create code with link metadata public function link($args) { extract($args); if (preg_match('/^http:\/\//', $url) || preg_match('/^https:\/\//', $url)) { $this->data = $url; } else { $this->data = "http://".$url; } } // create code with bookmark metadata public function bookmark($args) { extract($args); $this->data = "MEBKM:TITLE:".$title.";URL:".$url.";;"; } // create text qr code public function text($args) { extract($args); $this->data = $text; } // create code with sms metadata public function sms($args) { extract($args); $this->data = "SMSTO:".$phone.":".$text; } // create code with phone number public function phone_number($args) { extract($args); $this->data = "TEL:".$phone; } // create code with mecard metadata public function contact_info($args) { extract($args); $this->data = "MECARD:N:".$name.";ADR:".$address.";TEL:".$phone.";EMAIL:".$email.";;"; } // create code wth email metadata public function email($args) { extract($args); $this->data = "MATMSG:TO:".$email.";SUB:".$subject.";BODY:".$message.";;"; } // create code with geo location metadata public function geo($args) { extract($args); $this->data = "GEO:".$lat.",".$lon.",".$height; } // create code with wifi configuration metadata public function wifi($args) { extract($args); $this->data = "WIFI:T:".$type.";S".$ssid.";".$pass.";;"; } // TODO // create code with i-appli activating meta data public function iappli($adf, $cmd, $param) { $param_str = ""; foreach($param as $val) { $param_str .= "PARAM:".$val["name"].",".$val["value"].";"; } $this->data = "LAPL:ADFURL:".$adf.";CMD:".$cmd.";".$param_str.";"; } // create code with gif or jpg image, or smf or MFi of ToruCa files as content public function content($args) { extract($args); $this->data = "CNTS:TYPE:".$type.";LNG:".$size.";BODY:".$content.";;"; } private function get_url_params() { $params = array( 'cht' => 'qr', 'chs' => $this->dimensions, 'chld' => $this->quality, 'chl' => (($this->escape == 'html') ? urlencode($this->data) : $this->data), ); // Colour is optional if ($this->colour) { $params['chf'] = $this->colour; } return http_build_query($params, '', '&'); } // get image public function get_image(){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->api); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $this->get_url_params()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response = curl_exec($ch); curl_close($ch); return $response; } // get link for image public function get_link($follow=false){ return $this->api.'?'.$this->get_url_params(); } // force image download public function download_image($file){ header('Content-Description: File Transfer'); header('Content-Type: image/png'); header('Content-Disposition: attachment; filename=qr_code.png'); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); ob_clean(); flush(); echo $file; } }