plugins:mobilewithsinglepage:mobilewithsinglepage_code2

<?php
 
/**
 * NP_MobileWithSinglePage 2.1.0
 * 携帯電話用にページ内容を変更
 */
 
 /*
  * Copyright (C) 2006-2007 NKJG
  *
  * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  * 
  * In addition, as a special exception, NKJG gives
  * permission to link the code of this program with those files in the PEAR
  * library that are licensed under the PHP License (or with modified versions
  * of those files that use the same license as those files), and distribute
  * linked combinations including the two. You must obey the GNU General Public
  * License in all respects for all of the code used other than those files in
  * the PEAR library that are licensed under the PHP License. If you modify
  * this file, you may extend this exception to your version of the file,
  * but you are not obligated to do so. If you do not wish to do so, delete
  * this exception statement from your version.
 */
 
require_once (dirname(__FILE__).'/sharedlibs/sharedlibs.php');
require_once ('nkjg/pluginextra.php'); // プラグインの共通部分
require_once ('nkjg/pluginoptioncreator.php'); // オプション作成
 
define('PLUG_MOBILEWITHSINGLEPAGE_SKIN_DELIM', '/');
define('PLUG_MOBILEWITHSINGLEPAGE_SKIN_DEFAULTNAME', 'mobile');
 
 
class NP_MobileWithSinglePage extends SHAREDLIBS_NKJG_PLUGINEXTRA {
  var $isStarted = false; // バッファリング状況
  var $aSkinName = false; // スキンのリスト
  var $toEncodeComment = false; // コメントをエンコードする
  var $isMobile = false;
  var $aMobileInfo = null;
 
  function getName() { return PLUG_MOBILEWITHSINGLEPAGE_TEXT_PLUGINNAME; }
  function getAuthor() { return 'NKJG'; }
  function getVersion() { return '2.1.0 beta'; }
  function getURL() { return 'http://japan.nucleuscms.org/wiki/plugins:mobilewithsinglepage'; }
  function getDescription(){ return PLUG_MOBILEWITHSINGLEPAGE_TEXT_DESCRIPTION; }
 
  function getEventList() {
    return array(
      'PostAuthentication',
      'PreSendContentType',
      'InitSkinParse',
      'PreSkinParse',
      'PostSkinParse',
      'FormExtra',
      'ValidateForm',
      'PreAddComment',
      );
  }
 
  function init() {
    $this->aMobileInfo = array();
    $this->incLangFile();
  }
 
  //////// インストール・オプション ////////
  function install() {
    $objOptionCreator =& new SHAREDLIBS_NKJG_PLUGINOPTIONCREATOR(&$this);
    $objOptionCreator->createGlobalOption_YesNo('changeSkin', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_CHANGESKIN, 'yes'); // since 2.1.0
    $objOptionCreator->createGlobalOption_Text('skinName', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_SKINNAME);
 
    $objOptionCreator->createGlobalOption_YesNo('conversion', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_CONVERSION, 'yes'); // since 2.1.0
    $objOptionCreator->createGlobalOption_Select(
      'imgOperate',
      PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_IMGOPERATE,
      array(
        PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_IMGOPERATE_TOTEXT => 'text',
        PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_IMGOPERATE_TOLINK => 'link',
        PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_IMGOPERATE_NO_CONVERT => 'no',
        )
      );
    $objOptionCreator->createGlobalOption_YesNo('removeQuot', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_REMOVEQUOT, 'yes');
    $objOptionCreator->createGlobalOption_YesNo('useHankaku', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_USEHANKAKU, 'yes');
    $objOptionCreator->createGlobalOption_Text('tagsNotRemove', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_TAGSNOTREMOVE, 'html|head|title|body|h1|h2|h3|h4|h5|h6|form|input|label|textarea|ul|ol|li|br|hr|p|div|table|tr|td|th|img|a|dl|dt|dd');
    $objOptionCreator->createGlobalOption_Text('attributesNotRemove', PLUG_MOBILEWITHSINGLEPAGE_TEXT_OPTION_ATTRSNOTREMOVE, 'id|src|name|href|alt|action|method|enctype|accept|accpept-charset|value|type|for|title|http-equiv|content|scheme|accesskey');
  }
 
  function event_PostAuthentication($data) {
    global $CONF;
    if (!$CONF['UsingAdminArea']) {
      $userAgent = serverVar('HTTP_USER_AGENT');
      require_once('Net/UserAgent/Mobile.php');
      $objUAMobile =& Net_UserAgent_Mobile::factory($userAgent);
      if (!$objUAMobile->isNonMobile() && !$objUAMobile->isError()) {
        $this->isMobile = true;
        $this->aMobileInfo['carrierLongName'] = $objUAMobile->getCarrierLongName();
        $this->aMobileInfo['carrierShortName'] = $objUAMobile->getCarrierShortName();
        $this->aMobileInfo['name'] = $objUAMobile->getName();
        $this->aMobileInfo['version'] = $objUAMobile->getVersion();
        $objDisplay = $objUAMobile->getDisplay();
        if (!PEAR::isError($objDisplay)) {
          $this->aMobileInfo['height'] = $objDisplay->getHeight();
          $this->aMobileInfo['width'] = $objDisplay->getWidth();
          $this->aMobileInfo['color'] = $objDisplay->isColor();
          $this->aMobileInfo['depth'] = $objDisplay->getDepth();
        }
      }
    }
  }
 
  function event_InitSkinParse($data) {
    if ($this->isMobile && $this->getOption('changeSkin') != 'no') {
      $this->changeSkin(&$data['skin']);
    }
  }
 
  // スキン変更
  function changeSkin(&$skin) {
    $currentSkinName = $skin->getName();
    $newSkinName = $this->_getNewSkinName($currentSkinName);
    if ($newSkinName != $currentSkinName) {
      $newSkin =& SKIN::createFromName($newSkinName);
      // copied from NP_SkinSwitcher.php
      $skin->SKIN($newSkin->getID()); 
    }
  }
 
  // 変更するスキン名の決定
  function _getNewSkinName($baseName) {
    $result = $baseName;
    $carrierName = trim(strtolower($this->aMobileInfo['carrierLongName']));
    $optionName = $this->getOption('skinName');
    $delim = PLUG_MOBILEWITHSINGLEPAGE_SKIN_DELIM;
 
    $aSkinName = array();
    if ($optionName) {
      $aSkinName[] = ($optionName . $delim . $carrierName);
      $aSkinName[] = ($optionName);
    }
    $aSkinName[] = ($baseName . $delim . $carrierName);
    $aSkinName[] = ($baseName . $delim . PLUG_MOBILEWITHSINGLEPAGE_SKIN_DEFAULTNAME);
 
    $aSkinList = $this->_getSkinList();
 
    foreach ($aSkinName as $skinName) {
      if (in_array($skinName, $aSkinList)) {
        $result = $skinName;
        break;
      }
    }
 
    return $result;
  }
 
  function event_PreSendContentType($data) {
    if ($this->isMobile && $this->getOption('conversion') != 'no') {
      $data['charset'] = 'Shift_JIS';
      $data['contentType'] = 'text/html';
    }
  }
 
  function event_PreSkinParse($data) {
    if ($this->isMobile) {
      // キャッシュはさせない
      header('Pragma: no-cache');
      header('Cache-Control: no-cache, must-revalidate');
 
      if ($this->getOption('conversion') != 'no') {
        ob_implicit_flush(false);
        $this->isStarted = ob_start(array(&$this, 'doConvert'));
      }
    }
  }
 
  function event_PostSkinParse($data) {
    if ($this->isStarted) {
      ob_end_flush();
    }
  }
 
  function doConvert($strHTML) {
    $strHTML = $this->doConvert_HTML($strHTML);
    $strHTML = $this->doConvert_encoding($strHTML);
    if ($this->getOption('useHankaku') != 'no') {
      $strHTML = $this->doConvert_hankaku($strHTML);
    }
 
    return $strHTML;
  }
 
  function doConvert_HTML($strHTML) {
    $aTagNotRemove = explode('|', strtolower($this->getOption('tagsNotRemove')));
    $aAttrNotRemove = explode('|', strtolower($this->getOption('attributesNotRemove')));
    $removeQuot = ($this->getOption('removeQuot') != no);
    $imgOperate = $this->getOption('imgOperate');
 
    $handler =& new PLUG_MOBILEWITHSINGLEPAGE_HTMLCONVERTER($aTagNotRemove, $aAttrNotRemove, $removeQuot, $imgOperate);
 
    require_once('XML/XML_HTMLSax.php');
    $parser =& new XML_HTMLSax();
    $parser->set_option(XML_OPTION_CASE_FOLDING);
    $parser->set_object($handler);
    $parser->set_element_handler('openHandler', 'closeHandler');
    $parser->set_data_handler('dataHandler');
 
    $parser->parse($strHTML);
 
    $strHTML = $handler->getResult();
 
    return $strHTML;
  }
 
  function doConvert_encoding($strHTML) {
    $strHTML = mb_convert_encoding($strHTML, 'SJIS', _CHARSET);
 
    return $strHTML;
  }
 
  function doConvert_hankaku($strHTML) {
    $strHTML = mb_convert_kana($strHTML, 'rnask', 'SJIS');
 
    return $strHTML;
  }
 
  function event_FormExtra($data) {
    switch ($data['type']) {
    case 'commentform-loggedin' :
    case 'commentform-notloggedin' :
      break;
    default :
      return;
    }
    if ($this->isMobile && $this->getOption('conversion') != 'no') {
      echo ('<input type="hidden" name="plug_mobilewithsinglepage" value="from_mobile" />');
    }
  }
 
  function event_ValidateForm($data) {
    if ($data['comment']) {
      if (postVar('plug_mobilewithsinglepage' == 'from_mobile')) {
        $this->toEncodeComment = true;
      }
    }
  }
 
  function event_PreAddComment($data) {
    if ($this->toEncodeComment) {
      $data['comment']['user'] = mb_convert_encoding($data['comment']['user'], _CHARSET, 'auto');
      $data['comment']['body'] = mb_convert_encoding($data['comment']['body'], _CHARSET, 'auto');
    }
  }
 
  function _getSkinList() {
    if ($this->aSkinName == false) {
      $aSkinName = array();
 
      $query = ('SELECT sdname FROM ' . sql_table('skin_desc'));
      $result = sql_query($query);
      while ($aResult = mysql_fetch_array($result)) {
        array_push($aSkinName, $aResult['sdname']);
      }
 
      $this->aSkinName = $aSkinName;
    }
 
    return $this->aSkinName;
  }
 
  // since 2.1.0
  function doSkinVar($skinType, $name = '') {
    $result = '';
    if (isset($this->aMobileInfo[$name])) {
      if ($this->aMobileInfo[$name] === true) {
        $result = 'yes';
      } elseif ($this->aMobileInfo[$name] === false) {
        $result = 'no';
      } else {
        $result = $this->aMobileInfo[$name];
      }
    }
    echo $result;
  }
 
  function doIf($key = '', $value = '') {
    $result = false;
    if ($key != '') {
      if (isset($this->aMobileInfo[$name])) {
        if ($value != '') {
          if (is_numeric($value)) {
            $result = (intval($this->aMobileInfo[$name]) <= intval($value));
          } else {
            $result = ($this->aMobileInfo[$name] == $value);
          }
        } else {
          $result = !!($this->aMobileInfo[$name]);
        }
      }
    } else {
      $result = $this->isMobile;
    }
    return $result;
  }
}
 
 
 
 
 
// PEAR::XML_HTMLSaxを使ってみる (間違いなく遅いけど)
class PLUG_MOBILEWITHSINGLEPAGE_HTMLCONVERTER {
  var $aTagNotRemove; // 削除されないタグ
  var $aAttrNotRemove; // 削除されない属性名
  var $removeQuot; // 引用符を削除するかどうか
  var $imgOperate; // IMG要素の処遇
 
  var $isEmpty = false; // bool "直前の要素が開始タグである"
  var $aNestLevel = 0; // a要素のネストレベル(最低レベルのa要素のみタグを出力する)
  var $aVoidLevel = 0; // 無視要素のネストレベル
 
  var $result = ''; // 結果
 
  // 各種オプションのセット
  function PLUG_MOBILEWITHSINGLEPAGE_HTMLCONVERTER ($aTagNotRemove, $aAttrNotRemove, $removeQuot, $imgOperate) {
    $this->aTagNotRemove = $aTagNotRemove;
    $this->aAttrNotRemove = $aAttrNotRemove;
    $this->removeQuot = $removeQuot;
    $this->imgOperate = $imgOperate;
 
    // 空要素であることが認められている要素 (大文字は仕様)
    $this->emptyElement = array(
      'br',
      'area',
      'link',
      'img',
      'param',
      'hr',
      'input',
      'col',
      'base',
      'meta',
      );
 
    // タグだけでなく内容も表示しない要素
    $this->voidElement = array(
      'script',
      );
 
  }
 
  // 開始ハンドラ
  function openHandler(&$parser, $tagName, $aAttr) {
    $result = '';
    $tagName = strtolower($tagName);
 
    $result .= $this->endOfEmpty();
 
    if (in_array($tagName, $this->voidElement)) {
      $this->voidLevel++;
    } else if ($this->voidLevel == 0 && in_array($tagName, $this->aTagNotRemove)) {
      switch ($tagName) {
      case 'img' :
        $result .= $this->openHandler_img($aAttr);
        break;
      case 'a' :
        $result .= $this->openHandler_a($aAttr);
        break;
      default :
        $result .= $this->openHandler_default($tagName, $aAttr);
        break;        
      }
    }
 
    $this->result .= $result;
  }
 
  // img要素用開始ハンドラ
  function openHandler_img($aAttr) {
    $result = '';
 
    // 代替テキスト
    $altText = '';
    if (isset($aAttr['alt'])) {
      $altText = $aAttr['alt'];
    }
 
    switch ($this->imgOperate) {
    case 'text' : // テキストに変換する場合
      if ($altText !== '') {
        $result .= $altText;
        $this->isEmpty = false;
      }
      break;
 
    case 'link' : // リンクに変換する場合
      if ($altText === '') {
        $altText = '[image]'; // 代替テキストが空の場合は'[image]'で代替
      }
      $aNewAttr = $aAttr;
      $aNewAttr['href'] = $aNewAttr['arc']; // src属性をhref属性にする
      unset($aNewAttr['arc']);
      unset($aNewAttr['alt']);
 
      $result .= $this->openHandler_a($aNewAttr); // a要素(開始タグ)
      $result .= $altText;
      $this->isEmpty = false;
      break;
 
    default : // そのまま画像で出力する場合
      $result .= $this->openHandler_default('img', $aAttr);
    }
 
    return $result;
  }
 
  // a要素用開始ハンドラ
  function openHandler_a($aAttr) {
    $result = '';
 
    // 祖先にまだa要素がない場合のみa要素を作る
    if ($this->aNestLevel == 0) {
      $result .= $this->openHandler_default('a', $aAttr);
    }
 
    $this->aNestLevel++;
 
    return $result;
  }
 
  // 通常の開始ハンドラ
  function openHandler_default($tagName, $aAttr) {
    $result = '';
    $tagName = strtolower($tagName);
    $close = '';
    if (in_array($tagName, $this->emptyElement)) {
      $this->isEmpty = true;
    } else {
      $this->isEmpty = false;
    }
 
    $result .= ('<' . $tagName);
 
    foreach ($aAttr as $attrName => $attrValue) {
      $attrName = strtolower($attrName);
      if (in_array($attrName, $this->aAttrNotRemove)) {
        $quot = '"';
        $close = '';
        if ($this->removeQuot && $attrValue != '' && strpos($attrValue, ' ') === FALSE) {
          // 引用符削除モードで、なおかつ内容が空文字列でなくて、空白も含まないときに引用符を削除る
          $quot = '';
          if (!$this->isEmpty) {
            $close = ' '; // 引用符削除状態でタグが終わる場合はホワイトスペースを入れる
          }
        }
        $result .= (' ' . $attrName . '=' . $quot . trim($attrValue) . $quot);
 
      }
    }
 
    if (!$this->isEmpty) {
      $close .= '>';
    }
 
    $result .= $close;
 
    return $result;
  }
 
  // 終了ハンドラ
  function closeHandler(&$parser, $tagName) {
    $result = '';
    $tagName = strtolower($tagName);
    if (in_array($tagName, $this->voidElement)) {
      $this->voidLevel--;
    } else if ($this->voidLevel == 0 && in_array($tagName, $this->aTagNotRemove)) {
      switch ($tagName) {
      case 'img' :
        $result .= $this->closeHandler_img();
        break;
      case 'a' :
        $result .= $this->closeHandler_a();
        break;
      default :
        $result .= $this->closeHandler_default($tagName);
        break;        
      }
    }
 
    $this->result .= $result;
  }
 
  // img要素用終了ハンドラ
  function closeHandler_img() {
    $result = '';
 
    switch ($this->imgOperate) {
    case 'text' : // テキストに変換する場合
      break;
 
    case 'link' : // リンクに変換する場合
      $result .= $this->closeHandler_a(); // a要素(終了タグ)
      break;
 
    default : // そのまま画像で出力する場合
      $result .= $this->closeHandler_default('img');
    }
 
    return $result;
  }
 
  // a要素用終了ハンドラ
  function closeHandler_a() {
    $result = '';
 
    $this->aNestLevel--;
 
    if ($this->aNestLevel == 0) {
      $result .= $this->closeHandler_default('a');
    }
 
    return $result;
  }
 
  // 通常の終了ハンドラ
  function closeHandler_default($tagName) {
    $result = '';
    $tagName = strtolower($tagName);
    if ($this->isEmpty) {
      $result .= (' />');
    } else {
      $result .= ('</' . $tagName . '>');
    }
 
    $this->isEmpty = false;
 
    return $result;
  }
 
  // データ部のハンドラ
  function dataHandler(&$parser, $data) {
    $result = '';
 
    $result .= $this->endOfEmpty();
 
    if ($this->voidLevel == 0) {
      $result .= $data;
    }
 
    $this->result .= $result;
  }
 
  function endOfEmpty() {
    $result = '';
 
    if ($this->isEmpty) {
      $result .= ('>'); // かわいい→('>')
    }
 
    $this->isEmpty = false;
 
    return $result;
  }
 
  function getResult() {
    // 出力前に整形
    $strHTML = $this->result;
    $strHTML = preg_replace("!(\r|\n|\n\r)!", "\n", $strHTML);
    $strHTML = preg_replace("!\n\s+!", "\n", $strHTML);
    $strHTML = preg_replace("!\s+\n!", "\n", $strHTML);
    $strHTML = preg_replace("!\n+!", "\n", $strHTML);
    $strHTML = preg_replace("!^\n!", "", $strHTML);
 
    return $strHTML;
  }
}
 
?>
 
plugins/mobilewithsinglepage/mobilewithsinglepage_code2.txt · 最終更新: 2011/03/23 21:28 (外部編集)