Skip to content

Instantly share code, notes, and snippets.

@masao
Created January 1, 2011 23:15
Show Gist options
  • Save masao/762100 to your computer and use it in GitHub Desktop.
Save masao/762100 to your computer and use it in GitHub Desktop.
PukiWiki plugin for J-STAGE API
<?php
/*
* J-STAGE API plugin
*/
define('PLUGIN_JSTAGE_USAGE', '#jstage(issn=xxxx-xxxx)');
define('JSTAGE_API_BASEURL', 'http://api.jstage.jst.go.jp/searchapi/do');
define('DEFAULT_HEADING_LEVEL', 2);
function plugin_jstage_convert()
{
static $_xml;
if (! isset($_xml)) $_xml = extension_loaded('xml');
if (! $_xml) return '#jstage: xml extension is not found<br />' . "\n";
$num = func_num_args();
if ($num == 0) return PLUGIN_JSTAGE_USAGE .'<br />' . "\n";
$argv = func_get_args();
$params = trim($argv[0]);
if (strlen($params) == 0) return ''. PLUGIN_JSTAGE_USAGE . '<br />' . "\n";
//return encode($params);
$timestamp = FALSE;
$cachehour = 24; // cache expires after a day (default)
$level = DEFAULT_HEADING_LEVEL;
if ($num > 1 && intval($argv[1]) > 0) {
$level = intval($argv[1]);
}
list($xml, $time) = plugin_jstage_get_xml($params, $cachehour);
$time = '';
if ($timestamp > 0) {
$time = '<p style="font-size:10px; font-weight:bold">Last-Modified:' .
get_date('Y/m/d H:i:s', $time) . '</p>';
}
$obj = new JSTAGE_TOC_html($xml, $level);
return $obj->toString($time);
}
class JSTAGE_TOC_html
{
var $items = array();
var $class = '';
var $level;
function JSTAGE_TOC_html($entry, $level)
{
$this->level = $level;
foreach ($entry as $item) {
$link = $item['ID'];
$title = $item['TITLE'];
$volume = $item['PRISM:VOLUME'];
$number = $item['PRISM:NUMBER'];
$spage = $item['PRISM:STARTINGPAGE'];
$link = '<a href="'. $link .'" title="'. $title .'" rel="nofollow">'. "$title</a> - $spage<br />\n";
if (! is_array($this->items[$volume]))
$this->items[$volume] = array();
if (! is_array($this->items[$volume][$number]))
$this->items[$volume][$number] = array();
$this->items[$volume][$number][$spage] = $link;
}
}
function toString($timestamp)
{
$retval = '';
$volumes = array_keys($this->items);
rsort($volumes);
foreach ($volumes as $volume) {
$retval .= "<h". $this->level .">Vol.$volume</h". $this->level .">\n";
$numbers = array_keys($this->items[$volume]);
sort($numbers);
$next_level = $this->level + 1;
foreach ($numbers as $number) {
$retval .= "<h$next_level>";
$retval .= "No.$number";
$retval .= "</h$next_level>";
$spages = array_keys($this->items[$volume][$number]);
sort( $spages );
foreach ($spages as $spage) {
$retval .= $this->items[$volume][$number][$spage];
}
}
}
return <<<EOD
<div{$this->class}>
$retval$timestamp
</div>
EOD;
}
}
// Get and save J-STAGE XML
function plugin_jstage_get_xml($params, $cachehour)
{
$buf = '';
$time = NULL;
$filename = CACHE_DIR . "jstage" . encode($params) . '.tmp';
if ($cachehour) {
// Remove expired cache
plugin_jstage_cache_expire($cachehour);
// Get the cache not expired
if (is_readable($filename)) {
$buf = join('', file($filename));
$time = filemtime($filename) - LOCALZONE;
}
}
if ($time === NULL) {
// Newly get XML
$url = PLUGIN_JSTAGE_BASEURL .'?service=3&'. $params;
$url = 'http://api.jstage.jst.go.jp/searchapi/do?service=3&'. $params;
//return array($cachehour,0);
$data = http_request($url);
if ($data['rc'] !== 200)
return array(FALSE, 0);
$buf = $data['data'];
//return array($buf,0);
$time = UTIME;
// Save XML into cache
if ($cachehour) {
$fp = fopen($filename, 'w');
fwrite($fp, $buf);
fclose($fp);
}
}
// Parse
$obj = new JSTAGE_TOC_XML();
return array($obj->parse($buf),$time);
}
// Remove cache if expired limit exeed
function plugin_jstage_cache_expire($cachehour)
{
$expire = $cachehour * 60 * 60; // Hour
$dh = dir(CACHE_DIR);
while (($file = $dh->read()) !== FALSE) {
if (substr($file, -4) != '.tmp') continue;
$file = CACHE_DIR . $file;
$last = time() - filemtime($file);
if ($last > $expire) unlink($file);
}
$dh->close();
}
// Get RSS and array() them
class JSTAGE_TOC_XML
{
var $items;
var $item;
var $is_item;
var $tag;
var $encoding;
function parse($buf)
{
$this->items = array();
$this->item = array();
$this->is_item = FALSE;
$this->tag = '';
// Detect encoding
$matches = array();
if(preg_match('/<\?xml [^>]*\bencoding="([a-z0-9-_]+)"/i', $buf, $matches)) {
$this->encoding = $matches[1];
} else {
$this->encoding = mb_detect_encoding($buf);
}
// Normalize to UTF-8 / ASCII
if (! in_array(strtolower($this->encoding), array('us-ascii', 'iso-8859-1', 'utf-8'))) {
$buf = mb_convert_encoding($buf, 'utf-8', $this->encoding);
$this->encoding = 'utf-8';
}
// Parsing
$xml_parser = xml_parser_create($this->encoding);
xml_set_element_handler($xml_parser, array(& $this, 'start_element'), array(& $this, 'end_element'));
xml_set_character_data_handler($xml_parser, array(& $this, 'character_data'));
if (! xml_parse($xml_parser, $buf, 1)) {
return(sprintf('XML error: %s at line %d in %s',
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser), $buf));
}
xml_parser_free($xml_parser);
return $this->items;
}
function escape($str)
{
// Unescape already-escaped chars (&lt;, &gt;, &amp;, ...) in RSS body before htmlspecialchars()
$str = strtr($str, array_flip(get_html_translation_table(ENT_COMPAT)));
// Escape
$str = htmlspecialchars($str);
// Encoding conversion
$str = mb_convert_encoding($str, SOURCE_ENCODING, $this->encoding);
return trim($str);
}
// Tag start
function start_element($parser, $name, $attrs)
{
if ($this->is_item) {
$this->tag = $name;
} else if ($name == 'ENTRY') {
$this->is_item = TRUE;
}
}
// Tag end
function end_element($parser, $name)
{
if (! $this->is_item || $name != 'ENTRY') return;
$item = array_map(array(& $this, 'escape'), $this->item);
$this->item = array();
if (isset($item['UPDATED'])) {
$time = plugin_jstage_get_timestamp($item['UPDATED']);
} else if (isset($item['PUBDATE'])) {
$time = plugin_jstage_get_timestamp($item['PUBDATE']);
} else if (isset($item['DESCRIPTION']) &&
($description = trim($item['DESCRIPTION'])) != '' &&
($time = strtotime($description)) != -1) {
$time -= LOCALZONE;
} else {
$time = time() - LOCALZONE;
}
$item['_TIMESTAMP'] = $time;
$date = get_date('Y-m-d', $item['_TIMESTAMP']);
$this->items[] = $item;
$this->is_item = FALSE;
}
function character_data($parser, $data)
{
if (! $this->is_item) return;
if (! isset($this->item[$this->tag])) $this->item[$this->tag] = '';
$this->item[$this->tag] .= $data;
}
}
function plugin_jstage_get_timestamp($str)
{
$str = trim($str);
if ($str == '') return UTIME;
$matches = array();
if (preg_match('/(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(([+-])(\d{2}):(\d{2}))?/', $str, $matches)) {
$time = strtotime($matches[1] . ' ' . $matches[2]);
if ($time == -1) {
$time = UTIME;
} else if ($matches[3]) {
$diff = ($matches[5] * 60 + $matches[6]) * 60;
$time += ($matches[4] == '-' ? $diff : -$diff);
}
return $time;
} else {
$time = strtotime($str);
return ($time == -1) ? UTIME : $time - LOCALZONE;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment