if (IN_serendipity !== true) { die ("Don't hack!"); } // Probe for a language include with constants. Still include defines later on, if some constants were missing $probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php'; if (file_exists($probelang)) { include $probelang; } include_once dirname(__FILE__) . '/lang_en.inc.php'; class xmlHandler { var $inTagState; var $curTagState; var $itemCounter; var $startTag; var $elementNames; var $xmlReturnData; var $xmlParser; var $xmlData; var $error; function setElementNames($arrayNames) { $this->elementNames = $arrayNames; } function setStartTag($sTag) { $this->startTag = $sTag; } function startElementHandler($xmlParser, $elementName, $elementAttribs) { if($elementName == $this->startTag) { $this->inTagState = 1; } if($this->inTagState == 1) { $this->curTagState = $elementName; } else { $this->curTagState = ''; } } function endElementHandler($xmlParser, $elementName) { $this->curTagState = ''; if($elementName == $this->startTag) { $this->itemCounter++; $this->inTagState = 0; } } function characterDataHandler($xmlParser, $xmlData){ if($this->curTagState == '' || $this->inTagState == 0) { return; } foreach($this->elementNames as $eNames) { if($this->curTagState == $eNames) { $strLoName = strtolower($eNames); // be sure to append character data, because the parser can call this function // multiple times in a tag, and all the calls should be appended together. $this->xmlReturnData[$this->itemCounter]["$strLoName"] .= $xmlData; } } } function xmlParse() { $this->inTagState = 0; $this->curTagState = ''; $this->itemCounter = 0; $this->xmlReturnData = array(); $this->error = ''; if(!($this->xmlParser = xml_parser_create("UTF-8"))) { $this->error = "Couldn't create XML parser!"; } xml_set_object($this->xmlParser, $this); xml_set_element_handler($this->xmlParser, "startElementHandler", "endElementHandler"); xml_set_character_data_handler($this->xmlParser, "characterDataHandler"); if(!xml_parse($this->xmlParser, $this->xmlData, true)) { $this->error = xml_error_string(xml_get_error_code($this->xmlParser)); } xml_parser_free($this->xmlParser); return $this->xmlReturnData; } function setXmlData($data) { $this->xmlData = $data; } function getXmlData() { return $this->xmlData; } function getErr() { return $this->error; } } class picasaXmlParser { var $inImages; var $itemCounter; var $xmlReturnData; var $xmlParser; var $error; var $imagePathTags; var $charData; var $albumPathEscaped; function startElementHandler($xmlParser, $elementName, $elementAttribs) { if(0 == strcasecmp($elementName, 'images')) { $this->inImages = true; } } function endElementHandler($xmlParser, $elementName) { $lowerElementName = strtolower($elementName); if($lowerElementName == 'images') { $this->inImages = false; } else if($lowerElementName == 'image') { $this->itemCounter++; } else if($this->inImages) { $value = trim($this->charData); if(array_key_exists($lowerElementName, $this->imagePathTags)) { $value = $this->albumPathEscaped . '/' . rawurlencode($value); $value = str_replace('%2F', '/', $value); } $this->xmlReturnData['images'][$this->itemCounter][$elementName] = $value; } else { $this->xmlReturnData[$elementName] = trim($this->charData); } $this->charData = ''; } function characterDataHandler($xmlParser, $xmlData) { // be sure to append character data, because the parser can call this function // multiple times in a tag, and all the calls should be appended together. $this->charData .= $xmlData; } function xmlParse($albumPath) { $this->inImages = false; $this->curTag = ''; $this->itemCounter = 0; $this->xmlReturnData = array(); $this->imagePathTags = array( 'previmage' => NULL, 'firstimage' => NULL, 'itemlargeimage' => NULL, 'nextimage' => NULL, 'nextthumbnail' => NULL, 'previmage' => NULL, 'prevthumbnail' => NULL, 'lastimage' => NULL, 'lastthumbnail' => NULL, 'itemthumbnailimage' => NULL ); $this->charData = ''; $splitPath = explode("/", $albumPath); $splitEncodedPath = array(); foreach($splitPath as $elt) { $splitEncodedPath[] = rawurlencode($elt); } $this->albumPathEscaped = implode("/", $splitEncodedPath); $this->error = ''; $xmlStr = file_get_contents($albumPath . '/index.xml'); if(!$xmlStr || $xmlStr == '') { $this->error = PLUGIN_EVENT_PICASA_ERR_INDEXNOTFOUND." ($albumPath)"; return; } if(! preg_match('@<\?xml@', $xmlStr)) { // repair broken xml generated by picasa.. $xmlStr = ''.$xmlStr; } if(!($this->xmlParser = xml_parser_create("UTF-8"))) { $this->error = "Couldn't create XML parser!"; return; } xml_parser_set_option($this->xmlParser, XML_OPTION_CASE_FOLDING, 0); xml_set_object($this->xmlParser, $this); xml_set_element_handler($this->xmlParser, "startElementHandler", "endElementHandler"); xml_set_character_data_handler($this->xmlParser, "characterDataHandler"); if(!xml_parse($this->xmlParser, $xmlStr, true)) { $this->error = xml_error_string(xml_get_error_code($this->xmlParser)); } xml_parser_free($this->xmlParser); return $this->xmlReturnData; } function getErr() { return $this->error; } } class serendipity_event_picasa extends serendipity_event { function introspect(&$propbag) { global $serendipity; $propbag->add('name', PLUGIN_EVENT_PICASA_NAME); $propbag->add('description', PLUGIN_EVENT_PICASA_DESC); $propbag->add('event_hooks', array( 'frontend_display' => true, 'external_plugin' => true )); $propbag->add('stackable', false); $propbag->add('author', 'Thomas Nesges, Greg Greenway'); $propbag->add('version', '1.13'); $propbag->add('requirements', array( 'serendipity' => '0.8', 'smarty' => '2.6.7', 'php' => '4.1.0' )); $propbag->add('groups', array('IMAGES')); $this->markup_elements = array( array( 'name' => 'ENTRY_BODY', 'element' => 'body', ), array( 'name' => 'EXTENDED_BODY', 'element' => 'extended', ), array( 'name' => 'HTML_NUGGET', 'element' => 'html_nugget', ) ); $conf_array = array(); foreach($this->markup_elements as $element) { $conf_array[] = $element['name']; } $conf_array[] = 'picasapath'; $conf_array[] = 'showtitle'; $conf_array[] = 'jswindow'; $conf_array[] = 'smarty_template'; $conf_array[] = 'upload_image_size'; $conf_array[] = 'create_entry_after_upload'; $propbag->add('configuration', $conf_array); } function generate_content(&$title) { $title = PLUGIN_EVENT_PICASA_NAME; } function introspect_config_item($name, &$propbag) { switch($name) { case 'picasapath': $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_PATH); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_PATH_DESC); $propbag->add('default', ''); $propbag->add('type', 'string'); break; case 'showtitle': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_SHOWTITLE); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_SHOWTITLE_DESC); $propbag->add('default', "true"); break; case 'jswindow': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_JSWINDOW); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_JSWINDOW_DESC); $propbag->add('default', "true"); break; case 'smarty_template': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_SMARTY); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_SMARTY_DESC); $select_values['none'] = PLUGIN_EVENT_PICASA_PROP_SMARTY_NONE; $plugin_dir = dirname(__FILE__); if($handle = opendir($plugin_dir)) { while (false !== ($file = readdir($handle))) { if(preg_match('/\.tpl/i', $file)) { $select_values[$plugin_dir.'/'.$file] = ucwords(str_replace(array('.tpl', '_'), array('', ' '), $file)); } } closedir($handle); } $propbag->add('select_values', $select_values); $propbag->add('default', 'none'); break; case 'upload_image_size': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_UPLOAD_SIZE); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_UPLOAD_SIZE_DESC); $propbag->add('default', '640'); break; case 'create_entry_after_upload': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_PICASA_PROP_CREATE_ENTRY_AFTER_UPLOAD); $propbag->add('description', PLUGIN_EVENT_PICASA_PROP_CREATE_ENTRY_AFTER_UPLOAD_DESC); $propbag->add('default', "true"); break; default: $propbag->add('name', $name); $propbag->add('description', sprintf(APPLY_MARKUP_TO, $name)); $propbag->add('type', 'boolean'); break; } return true; } function event_hook($event, &$bag, &$eventData) { global $serendipity; $hooks = &$bag->get('event_hooks'); if (isset($hooks[$event])) { switch($event) { case 'frontend_display': $picasapath = $this->get_config('picasapath'); foreach ($this->markup_elements as $temp) { if (serendipity_db_bool($this->get_config($temp['name'], true)) && isset($eventData[$temp['element']]) && !$eventData['properties']['ep_disable_markup_' . $this->instance] && !isset($serendipity['POST']['properties']['disable_markup_' . $this->instance])) { $element = $temp['element']; if ($temp['name'] == 'ENTRY_BODY' || $temp['name'] == 'EXTENDED_BODY' || $temp['name'] == 'HTML_NUGGET') { while(preg_match('@\[picasa\s*([^\]]*)\](.*?)\[/picasa\]@', $eventData[$element], $matches)) { $attr = array(); $attributes = explode(' ', $matches[1]); foreach($attributes as $a) { $kv = explode('=', $a); $attr[$kv[0]] = preg_replace('@[\'"]@', '', $kv[1]); } $album = $matches[2]; if ($attr['path'] != "") { $albumpath = $attr['path'].'/'.$album; } else { $albumpath = $picasapath.'/'.$album; } $picasa = $this->picasa_album($albumpath, $attr['template']); $eventData[$element] = preg_replace('@'.quotemeta($matches[0]).'@', $picasa, $eventData[$element], 1); } } } } return true; break; case 'external_plugin': $param = explode('/', $eventData); $plugincode = array_shift($param); if($plugincode == 'picasa_pre_upload') { $this->picasa_pre_upload(); return true; } else if($plugincode == 'picasa_upload') { $this->picasa_upload(); return true; } else if($plugincode == 'picasa_upload_report_status') { $this->picasa_upload_report_error($param); return true; } return false; break; default: return false; } } else { return false; } } function picasa_album($album, $template="") { global $serendipity; $plugin_dir = dirname(__FILE__); $jswindow = $this->get_config('jswindow'); $showtitle = $this->get_config('showtitle'); if($template) { $searchpathes = array( $template, $plugin_dir.'/'.$template, $plugin_dir.'/'.$template.'.tpl', $plugin_dir.'/'.strtolower($template), $plugin_dir.'/'.strtolower($template).'.tpl', $plugin_dir.'/'.strtolower(preg_replace('/\s/', '_', $template)).'.tpl' ); foreach($searchpathes as $trytemplate) { if(file_exists($trytemplate)) { $smarty_template = $trytemplate; break; } } } else { $smarty_template = $this->get_config('smarty_template'); } $xh = new picasaXmlParser(); $xmlData = $xh->xmlParse($album); $xmlError = $xh->getErr(); if($xmlError != '') return $xmlError; $albumName = $xmlData['albumName']; $albumCaption = $xmlData['albumCaption']; $albumItemCount = $xmlData['albumItemCount']; foreach($xmlData['images'] as $ikey => $ivalue) { $xmlData['images'][$ikey]['itemCaption'] = htmlspecialchars($ivalue['itemCaption'], ENT_QUOTES, false); } if($smarty_template == 'none') { $album_code = "
[picasa]' . $albumDir . '[/picasa]
'; $entry['authorid'] = $serendipity['authorid']; $entry['exflag'] = false; $entry['allow_comments'] = 'true'; $entry['moderate_comments'] = 'false'; $id = serendipity_updertEntry($entry); $retUrl = $serendipity['baseURL'] . 'serendipity_admin.php?serendipity[action]=admin&serendipity[adminModule]=entries&serendipity[adminAction]=edit&serendipity[id]=' . $id; echo $retUrl; } else { $this->report_upload_result(PLUGIN_EVENT_PICASA_UPLOAD_SUCCESS); } } function report_upload_result($text) { global $serendipity; $encodedText = urlencode($text); echo $serendipity['baseURL'] . "index.php?/plugin/picasa_upload_report_status/$encodedText"; } function picasa_upload_report_error($text) { echo urldecode($text[0]); } function example() { $s = "Instructions for adding an upload button to Google Picasa:
\n"; $s .= "