2011年9月22日木曜日

カスタムBB(XOOPSショートコード)のご案内

XOOPSのプリロードに置くと、[bbcode]を自由に拡張できます。例えば、以下の様なニッチなbbcodeも自在に作れてコアハックもせずにサイト全体で利用できてとても便利です。

[xoops_imageurl] テンプレートの画像フォルダ文字列を取得
[mod_jump] 任意のモジュールのURIへ自動ジャンプ
[iine_bulletintopic_count] ブリティンに貼付けたいいねモジュールのカウント
[xoops_theme] テーマフォルダの文字列を取得
[pm_count] メッセージのカウントを取得
[d3comment_count] コメントのカウントを取得
[d3comment_unread] コメントに未読があるか取得

以下ソースをCustomBB.class.phpとしてpreloadへ保管下さい。

<?php
class CustomBB extends XCube_ActionFilter
{
    function preBlockFilter() {
        $this->mController->mRoot->mDelegateManager->add("MyTextSanitizer.XoopsCodePre",array(&$this,"BBCodePre"));
    }
    /*
     * Add Short code into Delegate BBCode
     */
    function BBCodePre(&$patterns, &$replacements, $allowimage) {

        // Replacement rules for [xoops_imageurl] tag
        $patterns[] = '/\[xoops_imageurl\]/es';
        $replacements[] = "CustomBB::xoops_imageurl();";     
        // Replacement rules for [mod_jump]
        $patterns[] = '/\[mod_jump (.*?)\]/es';
        $replacements[] = "CustomBB::mod_jump('\\1');";
        // Replacement rules for [iine_bulletintopic_count] tag
        $patterns[] = '/\[iine_bulletintopic_count (.*?)\]/es';
        $replacements[] = "CustomBB::iine_bulletintopic_count('\\1');";
        // Replacement rules for [xoops_theme] tag
        $patterns[] = '/\[xoops_theme\]/es';
        $replacements[] = "CustomBB::xoops_theme();";
        // Replacement rules for [pm_count] tag
        $patterns[] = '/\[pm_count (.*?)\]/es';
        $replacements[] = "CustomBB::pm_count('\\1');";
        $patterns[] = '/\[pm_count\]/es';
        $replacements[] = "CustomBB::pm_count();";
        // Replacement rules for [d3comment_count] tag
        $patterns[] = '/\[d3comment_count (.*?)\]/es';
        $replacements[] = "CustomBB::d3comment_count('\\1');";
        // Replacement rules for [d3comment_unread] tag
        $patterns[] = '/\[d3comment_unread (.*?)\]/es';
        $replacements[] = "CustomBB::d3comment_unread('\\1');";
    }
    /*
     * Make Shrot code return strings
     */
    function xoops_theme($args='') {
        return XOOPS_THEME_URL;
    }
    function xoops_imageurl($args='') {
        return $GLOBALS['xoopsTpl']->get_template_vars('xoops_imageurl');
    }
    function mod_jump($args='') {
        // Short code parser start
        $args = html_entity_decode(stripslashes($args));
        $args = preg_replace('/(")/',"",$args);
        $keyval = explode(" ",$args);
        preg_match('/^url=(.*)/',$keyval[0],$matches);
        // Short code parser end
        $ret = "";
        if ($matches){
            $ret = '<script type="text/javascript">window.location.href="';
            $ret .= XOOPS_URL . "/modules/" . $matches[1];
            $ret .= '";</script>';
            return $ret;
        }
    }
    function pm_count($args='') {
        global $xoopsDB;

        // Short code parser start
        $args = preg_replace('/(&quot;|")/',"",stripslashes($args));
        $keyval = explode(" ",$args);
        foreach($keyval as $k){
            preg_match("/(.*)=(.*)/",$k,$matches);
            $params[$matches[1]] = $matches[2];
        }       
        // Short code parser end
       
        $sql = "SELECT count(*) FROM " . $xoopsDB->prefix("message_inbox");
        switch ($params['type']){
            case 'unread':
                $sql .= " WHERE is_read=0";
                if ($params['from_uid']) $sql .= " AND from_uid=".$params['from_uid'];
        }
        $res = $xoopsDB->query($sql);
        list($cnt) = $xoopsDB->fetchRow($res);
        return $cnt;
    }
    function d3comment_count($args='') {
        global $xoopsDB;

        // Short code parser start
        $args = preg_replace('/(&quot;|")/',"",stripslashes($args));
        $keyval = explode(" ",$args);
        foreach($keyval as $k){
            preg_match("/(.*)=(.*)/",$k,$matches);
            $params[$matches[1]] = $matches[2];
        }       
        // Short code parser end
        $mydirname = "d3forum";
        $sql = "SELECT topic_posts_count FROM " . $xoopsDB->prefix($mydirname."_topics");
        if ($params['link_id']) $sql .= " WHERE topic_external_link_id=".$params['link_id'];
        $res = $xoopsDB->query($sql);
        list($cnt) = $xoopsDB->fetchRow($res);
        return $cnt;
    }
    function d3comment_unread($args='') {
        global $xoopsDB,$xoopsUser;

        // Short code parser start
        $args = preg_replace('/(&quot;|")/',"",stripslashes($args));
        $keyval = explode(" ",$args);
        foreach($keyval as $k){
            preg_match("/(.*)=(.*)/",$k,$matches);
            $params[$matches[1]] = $matches[2];
        }       
        // Short code parser end
        $mydirname = "d3forum";
        $sql = "SELECT t.topic_last_post_time, u2t.u2t_time FROM ".$xoopsDB->prefix($mydirname."_topics").
            " t LEFT JOIN ".$xoopsDB->prefix($mydirname."_users2topics")." u2t ON t.topic_id=u2t.topic_id AND u2t.uid="
            . $xoopsUser->uid();
        if ($params['link_id']) $sql .= " WHERE topic_external_link_id=".$params['link_id'];
        $res = $xoopsDB->query($sql);
        list($pt,$ut) = $xoopsDB->fetchRow($res);
        return $pt > $ut ? 1 : 0;
    }
    function iine_bulletintopic_count($args='') {
        global $xoopsDB;

        // Short code parser start
        $args = preg_replace('/(&quot;|")/',"",stripslashes($args));
        $keyval = explode(" ",$args);
        foreach($keyval as $k){
            preg_match("/(.*)=(.*)/",$k,$matches);
            $params[$matches[1]] = $matches[2];
        }
        // Short code parser end
        $mydirname = "bulletin";
        $sql = "SELECT count(id) FROM " . $xoopsDB->prefix("iine_votes") ." where dirname = '" . $mydirname. "' and content_id in (select storyid from ".$xoopsDB->prefix("bulletin_stories")." where topicid = ".$params['topic_id'] .")";
        //print($sql);
        $res = $xoopsDB->query($sql);
        list($cnt) = $xoopsDB->fetchRow($res);
        return $cnt;
    }
}
?>

2011年9月18日日曜日

XOOOPS ショートコード習作1

プライベートメッセージの受信総数、未読数、指定ユーザーIDからの未読数を表示する為のXOOOPS ショートコード

書式1:[pm_count type="unread" from_uid="1"] 返り値はユーザーID1からの未読数
書式2:[pm_count type="unread"]  返り値は未読数
書式3:[pm_count]  返り値はメッセージ総数



<?php
class CustomSanitizer extends XCube_ActionFilter
{
    function preBlockFilter() {
        $this->mController->mRoot->mDelegateManager->add("MyTextSanitizer.XoopsCodePre",array(&$this,"BBCodePre"));
    }
    /*
     * Add Short code into Delegate BBCode
     */
    function BBCodePre(&$patterns, &$replacements, $allowimage) {
        // Replacement rules for [pm_count] tag
        $patterns[] = '/\[pm_count (.*?)\]/es';
        $replacements[] = "CustomSanitizer::pm_count('\\1');";
        $patterns[] = '/\[pm_count\]/es';
        $replacements[] = "CustomSanitizer::pm_count();";
    }
    /*
     * Make Shrot code return strings
     */
    function pm_count($args='') {
        global $xoopsDB;

        // Short code parser start
        $args = preg_replace('/(&quot;|")/',"",stripslashes($args));
        $keyval = explode(" ",$args);
        foreach($keyval as $k){
            preg_match("/(.*)=(.*)/",$k,$matches);
            $params[$matches[1]] = $matches[2];
        }       
        // Short code parser end
       
        $sql = "SELECT count(*) FROM " . $xoopsDB->prefix("message_inbox");
        switch ($params['type']){
            case 'unread':
                $sql .= " WHERE is_read=0";
                if ($params['from_uid']) $sql .= " AND from_uid=".$params['from_uid'];
        }
        $res = $xoopsDB->query($sql);
        list($cnt) = $xoopsDB->fetchRow($res);
        return $cnt;
    }
}
?>

2011年7月29日金曜日

d3blogのコメントがWizMobileでエラーになる件

少々込み入っているのでブログにまとめる。

まず、いきなりリダイレクトされて面食らうのだが、WizMobileではpostメソッドで呼ばれたら$_GETパラメータは取得できないらしい。という事でPOSTメソッドを使うにも関わらず、URLにGETパラメータを埋め込んで呼び出している変則的な部分をPOSTパラメータに埋め込み直す。

xoops_trust_path/modules/d3blog /templates/inc_comment_form.html
themes/wmb_default/templates/d3blog/inc_comment_form.html
themes/mbxoops6/templates/d3blog/inc_comment_form.html


上記のいずれもpostメソッドなのにgetパラメータ渡しを目論んでいた。
<form name='d3blogCommentForm' id='d3blogCommentForm' action='<{$xoops_url}>/modules/<{$mydirname}>/index.php?page=comment_post' method='post'>


(そりゃないぜセニョール)なのでpostへ変更

<form name='d3blogCommentForm' id='d3blogCommentForm' action='<{$xoops_url}>/modules/<{$mydirname}>/index.php' method='post'>

  <!-- comment rule -->
  <div style="text-align: center; <{$smarty.const.MBX_FS_XSMALL}>">
    (<{$rule_text}>)
  </div>
  <{$smarty.const.MBX_BLANK_TAG}>

  <!-- hidden items -->
  <input type='hidden' name='page' id='page' value='comment_post' />

こんな感じで hidden items 欄へパラメータを埋め込み直す。しかーし、このpageという変数はgetでしか受け取ってくれない。という事で次は受け取り部にpost処理を追加

xoops_trust_path/modules/d3blog /main.php

$mytrustdirpath = dirname( __FILE__ ) ;

$page = preg_replace( '/[^a-zA-Z0-9_-]/' , '' , @$_GET['page'] );

の1行下に追加。

// Hacked by a.k.a Bluemoon
if (isset($_POST['page'])) $page = preg_replace( '/[^a-zA-Z0-9_-]/' , '' , @$_POST['page'] );

で、気を取り直してデバッグするとリダイレクトされる。しかしコメント投稿は成功していた。じゃリダイレクトがへんじゃねとさらにハックする。

xoops_trust_path/modules/d3blog /main/comment_post.php

以下、書込み成功後のリダイレクトがどーだったかというと


        if (!isset($comment_post_results)) {

            // if the comment is active, redirect to posted comment
            if ($comment->getVar('com_status') == XOOPS_COMMENT_ACTIVE) {
                redirect_header($redirect_page.'='.$com_itemid.'&amp;com_id='.$newcid.'&amp;com_rootid='.$com_rootid.'&amp;com_mode='.$com_mode.'&amp;com_order='.$com_order.'#comment'.$newcid, 2, _CM_THANKSPOST);
            } else {
                // not active, so redirect to top comment page
                redirect_header($redirect_page.'='.$com_itemid.'&amp;com_mode='.$com_mode.'&amp;com_order='.$com_order.'#comment'.$newcid, 2, _CM_THANKSPOST);
            }
        }
まあ、通常のブラウザなら問題ないんだけどWizMobile的にはきちんとXOOPS_URLが記載されていないのとNGらしい。という事でちゃんと頭から正式なURIを入れてみる。

        if (!isset($comment_post_results)) {
            // Hacked by a.k.a Bluemoon  start
            // if the comment is active, redirect to posted comment
            if ($comment->getVar('com_status') == XOOPS_COMMENT_ACTIVE) {
                $redirect = sprintf('%s/modules/%s/', XOOPS_URL, $mydirname) . $redirect_page.'='.$com_itemid.'&amp;com_id='.$newcid.'&amp;com_rootid='.$com_rootid.'&amp;com_mode='.$com_mode.'&amp;com_order='.$com_order.'#comment'.$newcid;
            } else {
                // not active, so redirect to top comment page
                $redirect = sprintf('%s/modules/%s/', XOOPS_URL, $mydirname) . $redirect_page.'='.$com_itemid.'&amp;com_mode='.$com_mode.'&amp;com_order='.$com_order.'#comment'.$newcid;
            }
            redirect_header($redirect, 2, _CM_THANKSPOST);
            // Hack end
        }


おK。やたらハマって他の作業しながらだが1週間位掛かってしまった。orz

最近マックに開発環境が移行したのでimodeシュミレータとかVMwareで済ましていたのだが、流石にVMwareにxampp入れるのも面倒なのでサーバ直でつついていたのがいけなかった.。しかも前に使っていたWindowsXPな環境がimodeシュミレータ何故かローカルにつながらず最後はauの openwave SDK 6.2でのソース表示に助けられた始末。これってもうダウンロードできないんじゃなかったっけ?(未確認)まあそんなこんなで、WindowsXPな環境はガラケーがある限り取っておかねばなるまい。

ああ、これらGPL V2なので訂正したら私のコメントも(いじってみた)記念に入れておいて欲しい。

2011年7月25日月曜日

Multiple fileupload class for Actung Baby

<?php
class commonCtrl {
    var $getUploadFileName = array();
    function commonCtrl(){
    }
    private function getRandomString($nLengthRequired = 8){
        $rdm_str = md5(uniqid(rand(), true));
        $rdm_str = substr($rdm_str,0,$nLengthRequired);
        return $rdm_str.date("ymdHis");
    }
    private function is_image($file){
        if (!(file_exists($file) && ($fp=fopen($file, "rb")))) return NULL;
        $data = fread($fp, 8);
        fclose($fp);
        if (strncmp("\x00\x00\x01\x00", $data, 4) == 0) {                                   // ICO
            return "ico";
        } else if (strncmp("\x89PNG\x0d\x0a\x1a\x0a", $data, 8) == 0) {                        // PNG
            return "pmg";
        } else if (strncmp('BM', $data, 2) == 0) {                                            // BMP
            return "bmp";
        } else if (strncmp('GIF87a', $data, 6) == 0 || strncmp('GIF89a', $data, 6) == 0) {    // GIF
            return "gif";
        } else if (strncmp("\xff\xd8", $data, 2) == 0) {                                    // JPEG
            return "jpg";
        } else {
            return NULL;
        }
    }
    /*
     * $files = $_FILES
     * $formName = form tag name as <input type="file".... />
     */
    function getUploadFiles($files,$formName,$prefix="img"){
        $this->getUploadFileName = array();
        for($i=0;$i<count($files[$formName]);$i++) {
            $myrow = array(
                'name' => $files[$formName]['name'][$i],
                'type' => $files[$formName]['type'][$i],
                 'tmp_name' => $files[$formName]['tmp_name'][$i],
                'error' => $files[$formName]['error'][$i],
                'size' => intval($files[$formName]['size'][$i])
            );
            if ( $myrow['size']>0 ){
                if ( !is_null($ext = $this->is_image($myrow['tmp_name'])) ){
                    $info = pathinfo($myrow['tmp_name']);
                    $upfile_name = $prefix . $this->getRandomString() . "." . $ext;
                    $upfile_path = XOOPS_ROOT_PATH."/uploads/" . $upfile_name;
                    move_uploaded_file($myrow['tmp_name'], $upfile_path);
                    chmod($upfile_path,0644);
                    $this->getUploadFileName[$i] = $upfile_name;
                }
            }
        }
        //var_dump($this->getUploadFileName); die;
        return $this->getUploadFileName;
    }
}
?>

2011年7月21日木曜日

The Actung Baby - Rapid MVC framework

This is a "tiny" MVC framework just only 50 lines. Completely Objective, Simple and easy to handle. See below as "index.php".
<?php
/***********************************************************************************
 * MVC ( Model View Control ) Action Program
 ******************************** License: GPLv3 ********************************
 * Copyright (C) 2011 Yoshi Sakai (A.K.A. bluemooninc)
 *  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 3 of the License, or
 *  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, see <http://www.gnu.org/licenses/>.
 ***********************************************************************************/
require '../../mainfile.php';
include XOOPS_ROOT_PATH."/header.php";
/***********************************************************************************
 * Model Section
 ***********************************************************************************/
$mydirname = basename( dirname( __FILE__ ) ) ;
$mymodpath = XOOPS_ROOT_PATH."/modules/$mydirname" ;
$model = isset($_GET['model']) ? htmlspecialchars($_GET['model'],ENT_QUOTES) : "category";
$model = isset($_POST['model']) ? htmlspecialchars($_POST['model'],ENT_QUOTES) : $model;
$ctrl = isset($_GET['ctrl']) ? $model . "_" . htmlspecialchars($_GET['ctrl'],ENT_QUOTES) : "";
$ctrl = isset($_POST['ctrl']) ? $model . "_" . htmlspecialchars($_POST['ctrl'],ENT_QUOTES) : $ctrl;
$myclass = $mymodpath . "/class/" . $model . ".php";
require( $myclass );
$handler = new ActionHandler($ctrl);
if ( !$ret = $handler->load() ){
    echo $handler->debug(); die;
}
/***********************************************************************************
 * Ctrl Section
 ***********************************************************************************/
if ( $ctrl ){
    if ( !$ret = $handler->$ctrl() ){
        echo $handler->debug(); die;
    }
}
/***********************************************************************************
 * View Section
 ***********************************************************************************/
$handler->assignRecords();$xoopsOption['template_main'] = "cartb2b_" . $model . ".html" ;
include( XOOPS_ROOT_PATH.'/footer.php' ) ;
?>

2011年7月17日日曜日

Jelly! はじめました。


WeeklyCMS収録後から、これってどうやるのとか自然と勉強会的な感じになって、懇親会の後も仕事するならJelly!やろうという感じでやってみました。

普段は別々の会社で働いているWeeklyCMSのメンバーですがさっそく打ち解けて楽しくリラックスしながらそれぞれの仕事をこなしていました。図書館とランチルームの中間みたいな雰囲気で仕事に集中したい時、雑談してくつろぎたいときとメリハリのある時間を作れたのが意外でこれはもしかしたら一人で仕事しているよりはかどるんじゃ無いかと思いました。

それに自分が詰まった所を呟くとすぐに相談に乗ってくれたり逆に自分のやり方を教えたりして、googleで調べるより速く出口へと導いてくれます。この働き方はノマドワーカーや自営業、SOHOで働く人にとってはとてもいい刺激になるし楽しい事この上ないです。

米西海岸ではじまった(たしかサンフランシスコ発祥と記憶しています)このJelly!という働き方、きっと日本でもはやりますよ。

What is Jelly!
http://www.workatjelly.com/

2011年7月7日木曜日

XOOPS Cube : 携帯対応モジュールのエラー表示

WizMobile で「照合用のワンタイム・チケットが見つかりませんでした。」というエラー表示がでる件について

Q:何故、この様なエラー表示が出るのですか?
A:セッションIDというユーザー識別情報が不明になった時表示されます。

 セッションIDとは:Webアプリケーションなどで、アクセス中のユーザの識別や行動の捕捉(セッション管理)のために付与される固有の識別情報。ユーザがアクセスしたりログインした際に発行され、一定時間アクセスが無かったりログアウトすると破棄されます。

Q:このエラーの出る機種は特定できますか?
A:2009年度以前のimodeブラウザ1.0規格のdocomo携帯で発生します。

Q:何故、imodeブラウザ1.0規格で発生しますか?
A:cookieという仕組みが利用できない為、URLでセッションを受け渡している為です。
Cookie とは、訪れた Web サイトによって作成され、あなたのコンピュータに保存される小さなファイルです。Cookie には、ユーザの識別や行動の捕捉(セッション管理)が保存されます
Q:URLでセッションを受け渡すと何故エラーがでますか?
A:サイトのプログラムとのデータ受け渡しに齟齬が出やすいため、WizMobile(携帯対応モジュール)は色々な方法で受け渡し情報をカバーしますが100%確実な方法が無い為です。

Q:解決策は?
A:cookieの保存が可能になった imodeブラウザ2.0の機種に移行してもらう必要があります。

Q:docomo携帯の買い替えを閲覧して来る人に強制できません。
A:imodeブラウザ1.0とURLによるセッション管理という仕組みでは確実に動作する事は技術上不可能です。「2009年度以前のdocomo機種(imodeブラウザ1.0)の場合は閲覧のみの対応となります」等のアナウンスが必要です。

 Q:何故セキィリティ対策が取れないのですか?
A: 簡単に説明するとブラウザのURL情報は簡単に盗み見る事ができコピーして為り変わる事が可能だからです。具体的にはセッションIDをURL上に保持した場合、HTTP Refererにより、他のドメインにセッションIDが漏洩します。また、ユーザの不注意により、セッションID付きのURLをソーシャルブックマークなどで公開したり、メールで知人に送信した結果、セッション情報が外部に漏洩するような事故が現実に発生しています。

Q:これから対応の予定はありますか?
A:ありません。前述の問題点に加えてCookieによるセッション管理でなければ問題が生じる事が明らかになってきている為です。

Q:どんな問題があるのですか?
A:技術的な詳細については以下URLや書籍を参照下さい。

http://d.hatena.ne.jp/ockeghem/20110615/p1

体系的に学ぶ 安全なWebアプリケーションの作り方
http://www.amazon.co.jp/exec/obidos/ASIN/4797361190/jisakucompile-22/

2011年7月1日金曜日

testarea の文字列もしくは MySQL text の文字列より任意の文字を切り出す関数

テキストエリア中から任意の文字だけを切り出したい場合の関数。
$textarea ="発着地を入力下さい。
出発地:上野
到着地:大井町
";
例えば、 pickupFromTextArea("出発地:",$textarea);
 とかすると、上野だけを取り出せます。
/*
 * Get one needle to line break from textarea strings
 */
function pickupFromTextArea($needle,$subject) {
  $pattern = "/{$needle}(.*)/";
  if (preg_match($pattern, $subject, $matches) === 1) {
    return trim($matches[1], "\r");
  }
  return false;
}

教えて!XOOのカテゴリにグループ権限を追加その2

さて、 教えて!XOOのカテゴリにグループ権限を追加した後、権限の無い場合は質問だけ表示して回答を表示しないというハックを紹介します。変更は以下ソース

/plzXoo/default/actions/detail.class.php
<?php

class default_DetailAction extends mojaLE_AbstractAction
{
    function execute(&$controller,&$request,&$user)
    {
        global $xoopsUser;    // bluemoon added
       
        exFrame::init(EXFRAME_PERM);
        // 閲覧権限のチェック
        exPerm::GuardRedirect('view_detail','index.php',_MD_PLZXOO_ERROR_PERMISSION);

        $id = isset($_REQUEST['qid']) ? intval($_REQUEST['qid']) : 0;
        $handler=&plzXoo::getHandler('question');

        $question=&$handler->get($id);
        if(!is_object($question))
            return VIEW_ERROR;

        // ステータスが1,2と異なるものは管理者以外キック
        if( ! in_array( $question->getVar('status') , array(1,2) ) ) {
            if( ! is_object( $GLOBALS['xoopsUser'] ) || ! $GLOBALS['xoopsUser']->isAdmin() )
                return VIEW_ERROR;
        }

        // hack by bluemoon: in
        $db =& Database::getInstance() ;
        $cid = $question->getVar('cid');
        $sql = "SELECT `groupid` FROM ".$db->prefix('plzxoo_category')." WHERE `cid`=".$cid ;
        list($groupid) = $db->fetchRow( $db->query( $sql) );
        if ( $xoopsUser ){
            $gids = array_merge( array(0,3) , $xoopsUser->getGroups());
            $permissionOkay = in_array( $groupid, $gids );
        }else{
            $gids = array(0,3);
            $permissionOkay = in_array( $groupid, $gids );
        }
        if ($permissionOkay){
            $handler=&plzXoo::getHandler('answer');
            $criteria = new Criteria('qid',$id);
            $criteria->setSort('input_date');
            $criteria->setOrder('DESC');
            $answers=&$handler->getObjects($criteria);
            $request->setAttribute('answers',$answers);
            //    $myrow['answer_body'] = _MD_PLZXOO_ERROR_PERMISSION;
        }
        // out
       
        $request->setAttribute('question',$question);
        return VIEW_SUCCESS;
    }

    function isSecure()
    {
        return false;
    }
}

?>

2011年6月24日金曜日

MySQLのインデックスと高速化について

インデックスの注意点

!=, <> はインデックスが使われない
LIKE 検索は前方一致のみでしかインデックスが使われない
OR や不等号を使った検索でインデックスが使われない場合がある。
ORDER BY するとインデックスが使われないパターンが出る。
EXPLAINを学ぶと高速にしょりできる。

あとは高速化のリンクをご紹介します。

参考になるリンクのご紹介

MySQLを高速化する10の方法

MySQLのEXPLAINを徹底解説!!

NoSQLにすると何がうれしいか?

NoSQLにすると何がうれしいか?それはスケールアウトする時にRDBがボトルネックになってNoSQLだとそれを回避できるからです。SNSやソーシャルゲーム等スケールアウト必至のアクセス数に達した時の手段です。企業がNoSQLにあまり関心が無いのはそこまで莫大なアクセス数をさばく必要がないからですね。また、Zingaの様にMySQLをクラスタ化してボトルネックを解消する手法もあります。それもまた1つの方法。
RoRで利用されているMongoDBがPHPでも利用可能なのを最近しりました。今後、NoSQLのCMSも出てくるかもしれませんね。
MongoDB
http://php.net/manual/ja/class.mongodb.php
NoSQLはRDBMSに取って代わるものなのか?
http://www.atmarkit.co.jp/flinux/rensai/noSQL/noSQL_01/01_2.html


MySQL Clusterを試す - クラスタ化した分散アドレス帳をつくる
http://journal.mycom.co.jp/special/2004/mysql/index.html
 

2011年6月20日月曜日

XSNSをメニューで選択した時にマイページを呼び出すプチ・ハック

最初にマイページが表示されるのがmixi流とお客さんに要望された場合のメモ。
<?php
require_once '../../mainfile.php';
require_once 'config.php';

// get も post もなければ mypage を表示
if(!$_GET && !$_POST){
    $page_name = 'mypage';
}else{
// パラメータが付いていればコミュニティのページを表示
    $page_name = isset($_REQUEST[XSNS_PAGE_ARG]) ? preg_replace('/[^0-9a-zA-Z_]/', '', $_REQUEST[XSNS_PAGE_ARG]) : 'index';
}
require_once XSNS_FRAMEWORK_DIR.'/loader.php';
require_once XSNS_TRUST_PATH.'/include/language.php';
xsns_load_language('main.php');
XsnsController::execute($page_name);
?>

2011年6月17日金曜日

WordPress のコア関数を使って外部ブログの更新情報一覧を表示する方法

WordPress コアの rss.php を使って外部の様々なブログから更新情報を拾い全てのブログを日付順に並び替えて表示する方法

buddypress/bp-activity/bp-activity-templatetag.php の関数の書き換えですが、他へも流用可。
echo 部分をリターンで返せば他でも使えるでしょう。

function bp_activity_get_rss() {
        $blogReadArr = file("./org/blog-URLs.txt"); // title TAB URL改行 のテキスト

        $iArray = array();
        foreach ($blogReadArr as $value) {
            $blogPartArr = explode("\t", $value);
            $blogTitle = $blogPartArr[0];
            $blogRSS = $blogPartArr[1];
            include_once(ABSPATH . WPINC . '/rss.php');
            $rss = fetch_rss("$blogRSS");
            $maxitems = 3;
            $items = array_slice($rss->items, 0, $maxitems);
           
            if ($items) {
                foreach ( $items as $item ){
                    $dt = NULL;
                    if (isset($item["dc"]["date"])) $dt = substr($item["dc"]["date"],5,14);
                    if (isset($item["pubdate"])){
                        $pdt = strtotime($item["pubdate"]);
                        $dt = date("m-d",$pdt)."T".date("H:i:s",$pdt);
                    }
                    $iArray[$dt] = array("date"=>$dt, "link"=>$item["link"], "title"=>$item["title"], "name"=>$blogTitle);
                }
            }
        }
        arsort($iArray);
        foreach ( $iArray as $item ){
            $link = $item["link"];
            $title = $item["title"];
            $name = $item["name"];
            $dt = substr($item["date"],0,5);
            echo "<li>$dt $name <a href=\"$link\" title=\"$title\" arget=\"_blank\">$title</a></li>";
        }
}

2011年6月8日水曜日

fgetcsv setlocale に頼らない CSV ファイルの読み込み関数

fgetcsv でCSVが簡単に読み込める場合は問題有りませんが、setlocaleでいろいろごにょごにょしないと文字化けにハマるし、設定に依存するのでサーバが変わると不具合が発生したりと、安心してつかえません。

fgetsで1行もってきてexplodeで切ればいいかというとCSV中に改行が入っていたり、ダブルクォーテーション文字列中に入っていたりする場合うまく行きません。

そこで、全てを網羅してきちんとCSVの1レコード分を読み込む関数を作りました。

    /*
     * Load CSV Line
     *         with CR+LF included in the columns
     *     Licenced GPL Ver.2: Copyright(c) Yoshi Sakai @ Bluemoon inc.
     *
     *     &$handle = File pointer
     *     $fieldNumber = Field number ( Max colmuns )
     */
    function fgets_csv( &$handle, $fieldNumber=0 ){
        if ( $fieldNumber==0 || feof($handle) ) return TRUE;
        $line = fgets($handle);                                    // Load 1 line anyway
        while ( 1 ){
            // Check CR+LF in the double cuotation and load
            $str = preg_replace('/"{2}/','"', $line);
            while ( substr_count($str,'"') % 2 > 0 ){
                if (feof($handle)) break;
                $line .= fgets($handle);
                $str = preg_replace('/"{2}/','"', $line);
            }
             // Check Field number
            $str = preg_replace('/"(.*?)"/',"", $line);            // cut double cuotation
            $n = substr_count($str,',');                        // count comma
            if ( feof($handle) || $n+1 >= $fieldNumber ) break;    // Field Ok?
        }       
        return $line;
    }

2011年6月6日月曜日

XOOPS Cube のユーザー名を変更可能にするハック

デフォルトでユーザー名を流し込んで、後からユーザー自身に変えさせるという場合XOOPS Cube はユーザー名変更できないという件に対応。本当はもっと煩雑な手続きを入れた方がいいんですけどとりあえずサクッと変更できる感じで。

modules/user/templtes/user_edituser.html

26行目付近に uname を入力可能にします。
      <!-- {$thisUser->getShow('uname')} -->
      <{xoops_input name=uname size=25 maxlength=25 value=$thisUser->getShow('uname')}>
  modules/user/forms/EditUserForm.class.php に uname追加

27行目付近
        $this->mFormProperties['uid'] =& new XCube_IntProperty('uid');
        $this->mFormProperties['uname'] =& new XCube_StringProperty('uname');
        $this->mFormProperties['name'] =& new XCube_StringProperty('name');

192行目付近
    function update(&$obj)
    {
        $obj->set('uname', $this->get('uname'));    // bluemooninc
        $obj->set('name', $this->get('name'));

2011年6月5日日曜日

ソニーの情報流出について

今週のWeeklyCMSではImpressCMSコミュニティからセキュリティについての放送をした事で、そろそろCMSとセキュリティについて特集を組まなければならないと思い始めました。

最近の流れとして情報流出にフォーカスが来ていると思います。思い起こせば、前回のOpenID特集もオバマ大統領の新戦略「サイバースペースにおける認証済み身元情報のための国家戦略(National Strategy for Trusted Identities in Cyberspace NSTIC)」もそうですし、最近話題のソニーの情報流出もそうです。

ソニーの場合ゲーム機だから比較的安全と見られていたという記事を見かけますが、情報流出はゲーム機ではなく、サーバですから他のPCと何ら条件は変わりません。 ジョージ・ホッツ氏によるプレイステーション3のハッキングに端を発し、これを知的財産権侵害としてソニー側が訴えた事でPS3を自由に使いたいハッカー達を刺激した様です。当初はDDoS攻撃による抗議行動だった様ですが、米国匿名ハッカーが「SCEが(配信サービスの)PSNをどのように管理しているのか」についての詳細な情報(SCEによるユーザー行動の監視、クレジットカード情報のテキストファイル送信、収集情報のオンライン・サーバ 上の配置)が明らかになり今回の史上最大の情報流出を招いた様です。

元記事「ソニー、ハッカーとの暗闘 脆弱だった「プレステネット」 個人情報流出 ゲームジャーナリスト 新 清士」

ここからは私の雑感ですが、「プレステネット」自体の開発がセキュリティ専門家が関わらずにアウトソーシングで作られ、通り一遍等の脆弱性スキャナーに通って安心して運用していたという様な感じではないでしょうか。オーダー先はシリコンバレーで、開発の中心はインドや中国等で世界的なアウトソーシングかもしれません。報道される内容からするとパスワードが平文だったりクレジットカードもテキストファイルだったり、収集した情報がオンラインサーバ上に有ったりと開発者目線で「へっ!?」という事が沢山ありました。

今回の事を教訓とするなら、安易なアウトソーシングはかえって高く付くという事でしょうか。そうは言っても、アウトソーシングは無くならないので、認証や個人情報はやはりNSTICの様な方向で調整されていくと思います。

では 外部認証を導入すれば安全は確保されるでしょうか?答えはNOです。サーバにデータがあり、外部とのインターフェースを持てばそこにセキュリティホールが発生する可能性があります。

という事で、インターネットがインフラとなっている昨今、 IPA(独立行政法人情報処理推進機構)にご協力頂き、各CMSコミュニティと皆さんと一緒に WeeklyCMS としてのセキュリティ特集を今後考えて行きたいと思います。

2011年6月4日土曜日

CMSとセキュリティ

今週はImpressCMSでセキュリティ対策について話題がでましたが、 CMS(特にPHP)で気にすべきセキュリティ項目は以下がメインとなります。 漏れていればコメント下さい。セエキュリティはいずれIPAと共同で何か放送を検討したいと思っています。

  1. クロスサイト・スクリプティング

  2. スクリプト(コード)・インジェクション

  3. SQL インジェクション

  4. ディレクトリ・トラバーサル

  5. クロスサイト・リクエスト・フォージェリ(CSRF)

    その他攻撃

    ヌルバイト攻撃、変数汚染攻撃、HTTPレスポンス分割攻撃、インクルード攻撃、eval利用攻撃、外部コマンド実行攻撃、ファイルアップロード攻撃、セッションハイジャック、スパムメール踏み台攻撃、DoSアタック、クリックジャック攻撃

 それぞれ、のキーワードに?と思ったらIPA(独立行政法人 情報処理推進機構セキュリティセンター)のホームページへお立ち寄り下さい。

http://www.ipa.go.jp/security/vuln/CWE.html 

2011年5月24日火曜日

I wrote lryics.

Title: The Ocean
Word and copyright by Yoshi Sakai ( Licence by GPL Ver.2)

Before, I had a too much pride. But I was so blind.
Now I have a mention. Cause you gave me an attention.
You know you can do nothing and thru. But you gave me a true.
So now, we hands on tight. we come over the hard days and night.

Into deep. Keep our mind.
Let's get together, We can help each other.

Into sea. See your mind.
So we can be free. Like a wave on the ocean.

Hug, each other.
 (Guitar solo)

Into deep. Keep our mind.
Let's get together, We can help each other.

Into sea. See my mind.
So we can be free. Like a wave on the ocean.

2011年5月22日日曜日

民間で「単一サイバー認証」導入を、米政府が新戦略

気になったツイートを後からたどってブログに構成しています。事のはじまりまりはAFPBBの記事のツイートからです。

http://www.afpbb.com/article/environment-science-it/it/2796095/7103232
【4月18日 AFP】米ホワイトハウス(White House)は15日、単一のオンライン認証サービスを民間主導で開発し、インターネットの信頼性向上やネット事業促進を目指す新たな国家戦略を発表した。

バラク・オバマ(Barack Obama)米大統領は声明で、「オンライン決済の信頼性とプライバシー保護をより高めることで、犯罪を防止するとともに、企業や消費者に信頼性を提供し、成長とイノベーションを促進する」と述べた。
新戦略「サイバースペースにおける認証済み身元情報のための国家戦略(National Strategy for Trusted Identities in Cyberspace NSTIC)」は、単一の認証サービスを民間主導で開発し、希望する個人に提供するというもの。
http://www.nist.gov/nstic/identity-ecosystem.html

米国サイトを見てみるとOpenIDは何も触れられていませんが、流れから言ってOpenID/Connect が第一候補だと思っています。逆に他の独自な認証がくればビックリな訳ですが、ともかくどういう流れになるのかはCMSやECサイトの構築や運営に関わる人なら気になる所ではないでしょうか?

という事で米国OpenID財団の理事長であるNatさんにWeeklyCMSでの講演を依頼した訳ですが先約の大学のキャンパスが複数に分かれていて当日の場所移動が物理的に無理という事が急遽判明しました。そこで、私ができる範囲でカバーし OpenID/Connect の概要とこれからを紹介したいと思います。そして、私の後は、OpenID/Twitter/Facebook(ソーシャル認証「これも気になりますが・・・」)のテクニカルに詳しい大和田氏へとバトンを渡す形で5月28日のマイクロソフト本社からのWeeklyCMS放送を行う予定です。

ではでは、皆様どんな講演になるかはこうご期待!

2011年5月20日金曜日

Calender view of each CMS

2011年5月6日金曜日

XOOPS Cube に IE6,7,8 でログインできない場合

FireFox,Safari等ではログインできるのにIEだとどのバージョンでもNGだという報告があり調べてみると、COOKIEの保存の仕方にIE独特のクセがある事がわかりました。

例えば www を抜かしてhttpにアクセスさせるやり方を最近多く見かけますが、サブドメインの有無のどちらにも対応してくれるのがfirefox等で、IEの場合DNSの設定によるかもしれませんがサブドメイン無しが優先的に記録される様です。(現状推測)

という訳で、www.hoge.com / hoge.com と両方からアクセスできてIEだけが「ログインしました」と表示されてログアウト状態になる場合はXOOPS_URL を見直してみましょう。私の場合はサブドメインをカットして正常にログインできる様になりました。

2011年5月2日月曜日

教えて!XOOのカテゴリにグループ権限を追加

今日は @minahito さんの plzXoo モジュールのハッキングについて。

ゲスト用には見えなくてユーザー登録すると見えるQ&Aが欲しいとのオーダーにより作成しました。


まずは、SQL。ユーザーグループを指定できればいいのでシンプルに整数で。
CREATE TABLE plzxoo_category (
    `cid` int(10) auto_increment,
    `pid` int(10) NOT NULL default 0,
    `name` varchar(255) NOT NULL default '',
    `description` text NOT NULL,
    `size` mediumint(5) NOT NULL default 0,
    `weight` mediumint(5) NOT NULL default 0,
    `groupid` tinyint(1) NOT NULL default 0,
    PRIMARY KEY (`cid`) ,
    KEY (`weight`) ,
    KEY (`pid`)
) TYPE=MyISAM;
 済んだら class CategoryEditFormで編集用のインターフェースを準備
<?php

require_once "exForm/Form.php";

class CategoryEditForm extends exActionFormEx
{
    var $cid_;
    var $pid_;
    var $name_;
    var $description_;
    var $groupid_;

    function fetch(&$master) {

        $this->pid_ = intval($_POST['pid']);
        // pid 妥当性検査
        if($this->pid_) {
            $handler=&plzXoo::getHandler('category');
            $obj=&$handler->get($this->pid_);
            if(!is_object($obj))
                $this->addError(_MD_PLZXOO_ERROR_PID_INJURY);
        }

        $this->name_ = trim($_POST['name']);
        if(!$this->name_) {
            $this->addError(_MD_PLZXOO_ERROR_NAME_REQUIRED);
        }
        if(!$this->validateMaxLength($this->name_, 255)) {
            $this->addError(_MD_PLZXOO_ERROR_NAME_SIZEOVER);
        }

        $this->description_ = $_POST['description'];

        $this->weight_ = intval( $_POST['weight'] ) ;
        $this->groupid_ = intval( $_POST['groupid'] ) ;
    }

    function load(&$master) {
        $this->cid_ = $master->getVar ( 'cid', 'e' );
        $this->pid_ = $master->getVar ( 'pid', 'e' );
        $this->name_ = $master->getVar ( 'name', 'e' );
        $this->weight_ = $master->getVar ( 'weight', 'e' );
        $this->groupid_ = $master->getVar ( 'groupid', 'e' );
        $this->description_ = $master->getVar ( 'description', 'e' );
    }

    function update(&$master) {
        $master->setVar ( 'pid', $this->pid_ );
        $master->setVar ( 'name', $this->name_ );
        $master->setVar ( 'weight', $this->weight_ );
        $master->setVar ( 'groupid', $this->groupid_ );
        $master->setVar ( 'description', $this->description_ );
    }
}


?>
language/hoge/admin.phpに変数追加して

define ( '_MD_A_PLZXOO_LANG_GROUPID','groupid' );

管理者画面に項目を追加。
<?php

require_once XOOPS_ROOT_PATH."/class/xoopsformloader.php";

class default_CategoryView_input
{
    function &execute (&$controller, &$request, &$user)
    {
        $editform=&$request->getAttribute('editform');
       
        $form = new XoopsThemeForm(_MD_A_PLZXOO_LANG_EDIT_CATEGORY,'Category','','POST');

        $form->addElement(new XoopsFormHidden('cid',$editform->cid_));

        $form->addElement(new XoopsFormText(_MD_A_PLZXOO_LANG_NAME,'name',64,255,$editform->name_));

        //-------------------------
        // 親カテゴリ
        //-------------------------
        $select =new XoopsFormSelect(_MD_A_PLZXOO_LANG_PARENT_CATEGORY,'pid',$editform->pid_);
            $select->addOption(0, _MD_A_PLZXOO_LANG_TOP );
            $categories=&$request->getAttribute('categories');
            foreach($categories as $category){
                $select->addOption($category->getVar('cid'),$category->getVar('name'));
            }

        $form->addElement($select);
        unset($select);

        $form->addElement(new XoopsFormDhtmlTextArea(_MD_A_PLZXOO_LANG_DESCRIPTION,'description',$editform->description_,6, 50));

        $form->addElement(new XoopsFormText(_MD_A_PLZXOO_LANG_WEIGHT,'weight',10,10,intval($editform->weight_)));
        $form->addElement(new XoopsFormText(_MD_A_PLZXOO_LANG_GROUPID,'groupid',10,10,intval($editform->groupid_)));

        $tray = new XoopsFormElementTray(_MD_A_PLZXOO_LANG_CONTROL);
        $tray->addElement( new XoopsFormButton ( '', 'submit', _MD_A_PLZXOO_LANG_SUBMIT, 'submit' ) );
        $tray->addElement( new XoopsFormButton ( '', 'reset', _MD_A_PLZXOO_LANG_RESET, 'reset' ) );
        $form->addElement($tray);

        $renderer = new mojaLE_Renderer($controller,$request,$user);
        $renderer->setTemplate('category_edit.tpl');

        $renderer->setAttribute('xoopsform',$form);

        return $renderer;
    }
}

?>

後は、表でロードした時にWHERE条件を追加 category.class.php

    /* class function */
    function getChildren( $cid )
    {
        // hack by bluemoon: Added groupid
        global $xoopsUser;
        if (is_object( $xoopsUser )){
            $gids = array_merge( array(0,3) , $xoopsUser->getGroups());
            $usergroups = implode( ",", $gids );
            if ( $usergroups ) $addwhere = " AND groupid in ($usergroups)";
        }else{
            $addwhere = " AND groupid in (0,3)";
        }
        $db =& Database::getInstance() ;
        $sql = "SELECT `cid`,`name`,`groupid` FROM ".$db->prefix('plzxoo_category').
            " WHERE `pid`=".intval($cid).$addwhere." ORDER BY `weight`" ;
        $result = $db->query( $sql ) ;
        $ret = array() ;
        while( list( $cid , $name ) = $db->fetchRow( $result ) ) {
            $ret[] = array( $cid => $name ) ;
        }

        return $ret ;
    }

これでOK。無事会員専用Q&Aの出来上がり。

2011年4月28日木曜日

WiMAX導入しました。

ゴールデンウィークを前に、お客さんのサポート体制を整備しないといけなくなりました。

お客様によっては休日がメインの場合もあります。個人向けサービスや販売は特にそうですね。

今までは、Wi-Fiや3Gを利用していましたが、都内ではなんとかなるも旅先では心もとないです。また、WeeklyCMSがマイクロソフトとタイアップして放送する事になってUSTでの回線確保も必須です。そこで問題となるのは、社内イントラのセキュリティです。通常一定数のクライアントを持つ企業ではプロキシを導入してセキュリティを確保するのが一般的です。そこれ解放するポートを限定しますが、USTの場合一般的なHTTPのポートではなく「1935,6667」のポートを使います。

で、普通に放送を開始しようと思うと蹴られます。
What firewall ports need to be opened for Ustream?
Open ports 1935 for both TCP/UDP in/out and the IRC chat port of 6667.

「これを明けて下さい!」と行った時に「本社セキュリティ部門と調整が必要です!」となるといつ決裁が降りるかわかりませんね。イベントを打つ部署ではスピード命です。

そんな時「じゃあ、回線をイベンターが確保します」とかの話になってしまうわけですが、3Gだと途切れる事多々有りですし、Wi-Fiはプロキシなのでポート空いてないという「放送できないヨ〜」という痛い状況になる訳です。USTできずorzというのはイベンターにとって致命的なので解決策を探っていた所 、WiMAXが有るじゃない!

 これなら下り最大20Mbps、上り最大6MbpsというUSTできる環境をゲットできる!という事でゴールデンウィーク目の前に急遽、UQ MAXとY電気でコラボしたルータ1円、月額3,880円を導入と相成りました。

Instagram画像(ムックと俺)

急遽、ガラケー一昨日買い増し、iPhone4去年9月、WiMAX昨日という「どんだけ〜」な通信環境を導入してしまったわけですが・・・。

これだけあるとどれか削らないといけません。

結局、iPhone4いらないよね〜と相成りました。違約金を考えるとただのWi-Fi端末として使う事になりそうです。

WiMAX+iPad2という新たな物欲が頭をもたげるのですが・・・続きはいずれまた。

2011年4月25日月曜日

XOOPS Cubeでメールアドレス・ログインを実現する実践編

メールログイン自体はGIJOE氏のpreloadで実現します。


以下、User_EmailLogin.class.php をpreloadフォルダへ入れます。
<?php

if( ! defined( 'XOOPS_ROOT_PATH' ) ) exit ;

class User_EmailLogin extends XCube_ActionFilter
{
    function preFilter()
    {
        $root =& XCube_Root::getSingleton();
        $root->mDelegateManager->add("Site.CheckLogin", array( &$this , 'checkLogin') ) ;
    }

    function checkLogin(&$xoopsUser)
    {
        if (is_object($xoopsUser)) {
            return;
        }

        $root =& XCube_Root::getSingleton();
        $root->mLanguageManager->loadModuleMessageCatalog('user');

        $userHandler =& xoops_getmodulehandler('users', 'user');
       
        $criteria =& new CriteriaCompo();
        $criteria->add(new Criteria('email', xoops_getrequest('uname')));
        $criteria->add(new Criteria('pass', md5(xoops_getrequest('pass'))));
       
       
        $userArr =& $userHandler->getObjects($criteria);
       
        if (count($userArr) != 1) {
            return;
        }
       
        if ($userArr[0]->get('level') == 0) {
            // TODO We should use message "_MD_USER_LANG_NOACTTPADM"
            return;
        }
       
        $handler =& xoops_gethandler('user');
        $user =& $handler->get($userArr[0]->get('uid'));
       
        $xoopsUser = $user;
   
        //
        // Regist to session
        //
        $root->mSession->regenerate();
        $_SESSION = array();
        $_SESSION['xoopsUserId'] = $xoopsUser->get('uid');
        $_SESSION['xoopsUserGroups'] = $xoopsUser->getGroups();
    }
}
?>

落とし穴はここから。

このままだとユーザー名の上限である25文字以上のメールアドレス使っているユーザーはメールアドレスを入力できません。

そこで、userモジュールのブロックテンプレートuser_block_login.htmlのmaxlengthを25文字でなくメールアドレスの最大文字長である255文字に変えます。
<form action="<{$xoops_url}>/user.php" method="post" style="margin-top: 0px;">
    <{$smarty.const._MB_USER_USERNAME}><br />
    <{xoops_input type=text name=uname size=12 value=$block.unamevalue maxlength=255 id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`block_uname"}><br />
    <{$smarty.const._MB_USER_PASSWORD}><br />
    <{xoops_input type=password name=pass size=12 maxlength=32 id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`block_pass"}><br />
<!--<label><{xoops_input type=checkbox name=rememberme value=On class=formButton}><{$smarty.const._MB_USER_REMEMBERME}></label><br />-->
    <input type="hidden" name="xoops_redirect" value="<{$xoops_requesturi}>" />
    <{xoops_input type=hidden name=op value=login id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`block_op"}>
    <{xoops_input type=submit name=submit value=$smarty.const._MB_USER_LOGIN id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`block_submit"}><br />
</form>
<{if $block.use_ssl == '1'}>
  <a href="javascript:openWithSelfMain('<{$block.sslloginlink}>', 'ssllogin', 300, 200);"><{$smarty.const._MB_USER_SECURE}></a>
<{/if}>
<a href="<{$xoops_url}>/lostpass.php"><{$smarty.const._MB_USER_LOSTPASS}></a>
<br /><br />
<{if $block.allow_register == '1'}>
  <a href="<{$xoops_url}>/register.php"><{$smarty.const._MB_USER_USERREG}></a>
<{/if}>
 これで一件落着と思いきやもう一つ見逃してはなりません。WizMobileで携帯対応しているならこれも手を入れる必要があります。

xoops_trust_pathのmodules/wizmobile/templates/main_login.html

これを開いてこっちも255文字へ上限を変更。これでやっとXOOPS Cube のメールアドレスログインが実現します。おっと、WziMobileのバージョンは最新版をダウンロードするのをお忘れなく。Ver0.51以降は簡単ログインでチケット処理が追加されてます。
<div id="<{$wizmobile_dirname}>Login">
  <form action="<{$xoops_url}>/modules/<{$wizmobile_dirname}>/index.php" method="post">
    <input type="hidden" name="act" value="Login" />
    <{wiz_gticket area=$wizmobile_dirname}>
    <input type="submit" value="<{"WIZMOBILE_LANG_SIMPLE_LOGIN"|wiz_constant}>" />
  </form>
  <span style="margin-top: 1em; color: #ff0000;"><{"WIZMOBILE_MSG_SIMPLE_LOGIN_CAUTION"|wiz_constant}></span>
</div>
<br />

<form action="<{$xoops_url}>/user.php" method="post" style="margin-top: 0px;">
  <{$smarty.const._MB_USER_USERNAME}><br />
  <input name="uname" id="<{$smarty.const.XOOPS_INPUT_DEFID_PREFIX}>_uname" type="text" size="12" maxlength="255" <{wizin_inputmode mode="alpha"}> /><br />
  <{$smarty.const._MB_USER_PASSWORD}><br />
  <input name="pass" id="<{$smarty.const.XOOPS_INPUT_DEFID_PREFIX}>_pass" type="password"  size="12" maxlength="32" <{wizin_inputmode mode="alpha"}> /><br/>
  <{xoops_input type=hidden name=op value=login id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`_op"}>
  <{xoops_input type=submit name=submit value=$smarty.const._MB_USER_LOGIN id="`$smarty.const.XOOPS_INPUT_DEFID_PREFIX`_submit"}>
</form>
<a href="<{$xoops_url}>/lostpass.php"><{$smarty.const._MB_USER_LOSTPASS}></a>
<br /><br />

<{if $wizmobile_userModuleConfig.allow_register == '1'}>
  <a href="<{$xoops_url}>/register.php"><{$smarty.const._MB_USER_USERREG}></a>
<{/if}>

以上、XOOPS Cube でメールアドレス・ログインを実現する実践編でした。

2011年4月21日木曜日

weblinks モジュールのソート条件について

今日のお題は、XOOPS Cube の weblinks モジュールについてです。

viewcat.php でカテゴリー内のリスト一覧が表示されますが、このリストの並び替えに地域を付け加えようという主旨です。

ページナビゲーションに地域(市区分と住所)での並び替えを加えると、単純に「カンマ区切りで昇順ね」とお願いしても無視されます。orz

class/weblinks_pagenavi_menu.php
function weblinks_pagenavi_menu()
{
    $this->happy_linux_pagenavi();

    $this->add_sort(_WLS_ADDRESSATOZ, 'city,addr',        'ASC');
    $this->add_sort(_WLS_ADDRESSZTOA, 'city,addr',        'DESC');
・・・以下略

で掘り出したコードはこちら。カンマ区切りが有れば$sort_arrの配列に律儀に項目をスタックして行きます。これでカンマ区切りで複数項目を並び替え指定できる様になりました。コメントアウトしている箇所が元ソースでその下のif文が追加となります。

class/weblinks_cat_view_handler.php
function &get_lid_array_by_cid_sort($cid, $sort, $limit=0, $start=0)
{
    $sort_arr = array();

    if ( $this->_conf['recommend_pri'] == 2 ){
        $sort_arr[] = 'recommend DESC';
    }

    if ( $this->_conf['mutual_pri'] == 2 ){
        $sort_arr[] = 'mutual DESC';
    }
    if ( isset($sort['sort']) && isset($sort['order']) ){
        //$sort_arr[] = $sort['sort'].' '.$sort['order'];
        if ( strpos($sort['sort'],",") === false ){
            $sort_arr[] = $sort['sort'].' '.$sort['order'];
        }else{
            $sortnames = explode(",",$sort['sort']);
            foreach ($sortnames as $s){
                $sort_arr[] = $s.' '.$sort['order'];
            }
        }
    }else{
        $sort_arr[] = 'lid ASC';
    }
    $orderby = implode(',', $sort_arr);
    $lid_arr =& $this->_link_catlink_handler->get_lid_array_by_cid_orderby($cid, $orderby, $limit, $start);
    return $lid_arr;
}

2011年4月4日月曜日

BuddyPressのテーマ編集

/wp-content/plugins/buddypress/bp-themes/index.php
 デフォルト・テーマは上記に配置。画像はこの下のフォルダ_incに位置する。
まあ、ここを触れば何とかテーマの体裁は整えられるという事。

2011年4月1日金曜日

XOOPS Cube サニタイズ関数の備忘録

XOOPS Cubeではサニタイズ用の関数が準備されています。文字列の取り扱いの際にはデータ取得元によって以下の処理を行う事により脆弱性のリスクを回避する事ができます。


【文字列型(テキストエリア以外)
・$_GET/$_POSTの通常表示・・・$myts->stripSlashesGPC 後 $myts->htmlSpecialChars
$_GET/$_POSTのフォーム内表示・・・$myts->stripSlashesGPC $myts->htmlSpecialChars
DB取得データの通常表示・・・$myts->htmlSpecialChars
DB取得データのフォーム内表示・・・$myts->htmlSpecialChars

【文字列型(テキストエリア)
$_GET/$_POSTの通常表示・・・$myts->previewTarea
$_GET/$_POSTのテキストエリア内表示・・・$myts->stripSlashesGPC $myts->htmlSpecialChars
DB取得データの通常表示・・・$myts->displayTarea
DB取得データのテキストエリア内表示・・・$myts->htmlSpecialChars

2011年3月24日木曜日

お客の質に要注意せよ

ピーター・ドラッガーもフィリップ・コトラーも語らなかった事に、客の質という物があります。

最初に顧客を見つけろ、顧客の要求にあった物は何かを探せとの師達の言葉ですが、そもそも客を装って、サービスをかすめ取る客を想定していません。

こちらが見積書・提案書、仕様概要書を出し、「では頼みます」という所まではOKですが・・・。

その後発注に至る前に「でも、具体的にイメージが湧かないので実際の事例(サンプル稼働)サイトを見せて下さい」とか、「仕様書がこちらの求めているレベルにまで達していません。もっと具体的に資料を作成してださい」とかで順々に資料を要求し設計書まで求めてくるとか。それは発注があってからと返答しても、「具体的に見極めるには資料が必要です」とかで平行線のままこちらは仕事を取りたいが為に資料を作り続ける訳です。

そんなこんなでメールや問い合わせ、資料作成への対応に時間と人的コストを相当つぎ込む事になる訳ですが、もっと具体的に云々と成果物により近い所まで引き延ばしておいて、彼らの狙いは、具体的な「稼働サイトの価値」や(下請けや社内で使える)「設計書」を引き出す事に意図があります。目的の物を手に入れたら、「あなたはこちらの要求を満たせなかった」「資料が後追いで、はじめから要求された物が用意できていない」といってハイさよならです。発注書を獲得しようとして動いた膨大な時間は戻ってきません。

ですから、きっぱりと法的な責任の発生する発注書を受け取るまでに相手に提示できる物を限定しましょう。稼働サイトはあくまでもサンプル品であり発注が無くてもいいレベルまでに限定してつくりましょう。仕様書もしかりです。費やす時間は発注が無くてもいいレベルに設定すべきです。

しかし、それ以上に大事なのは相手の態度です。明らかに高所から見下ろす様な客はマーケティング的に見てもエンゲージメントの対象ではありません。それはロイヤリティです。 あなたは膨大なマーケット中のたった1つの顧客に、しかも発注してもらっていない想定上の顧客に忠誠を誓うつもりですか?気をつけて下さい。見返りはゼロかもしれません。また、いかにもフレンドリーな態度で接してくるのも注意が必要です。ちょっと「お試し」気分なだけかもしれません。

ここら辺の話はビジネス・セミナーで学べるのでしょうか?オープンソースを生業として技術で生きている身として、同じ同業者同士、皆で騙されない様にもっと連帯して学んで行く場があってしかるべきだと思いました。

技術的な勉強会は多々あれど、我々技術者が直面する日々の生活に直結するビジネスの進め方に関する勉強会も大事だと思いませんか?

賛同する方、twitter ID @bluemooninc でお声を掛けて下さい。

本日は、質の悪い客に引っかかったボヤキにお付き合い頂きありがとうございました。

有限会社ブルームーン & XOOPS Cube Information事務局
代表取締役 酒井能克

2011年3月18日金曜日

XOOPS Cube, Weblinks, 一括登録にてカテゴリがセットされない不具合

WebLinksモジュールには、リンク一括登録 (管理者が登録項目を指定する )という機能がありますが、カテゴリが設定されない不具合がありました。

訂正箇所は以下の通りです。

weblinks/admin/bulk_manage.php 649行目付近
function _insert_link($cid, $arr)
{
    global $xoopsUser;
    $cid = intval($cid);

    if ( $cid <= 0 )
    {
        $this->_print_error( _AM_WEBLINKS_BULK_ERROR_CID );
        return false;
    }

// BUG : not set search field
    // Bugfix by bluemoon inc.
    // $arr['cid'] = array( $cid );
    $arr['uid'] = $xoopsUser->uid();
    $arr['cids'] = "$cid";

// BUG 4318: cannot register bulk links.
// Fatal error: Call to undefined method weblinks_link_edit_handler::add_link_to_link()
    $link_obj =& $this->_link_edit_handler->create_add_link_by_arr( $arr, true, false );
    // Enforced set by bluemoon inc.
    $link_obj->setVar('cids', $cid );
・・・以下省略

2011年3月16日水曜日

ブロックの強制的な非表示

XOOPS Cubeで、あるモジュールのindex.phpの時だけブロックを表示したくない。
そんな時は、header.phpをインクルードする前に、$show_rblock変数を宣言します。

たったこれだけで、ブロック表示をオフにする事ができるのです。ソース中からでも細かいブロック制御ができるのでとても便利です。
$show_rblock=0;

include 'header.php';

2011年3月14日月曜日

Donate to Japan earth quake.

Hi All,

If you try to donate for Japan Earthquake. I write here Japanese "RED-CROSS" office safely and trusty.

CITI-BANK Japan.

Given the impact of the tragedy, Citi has pledged 100 million yen and has established an account for donations to support the relief efforts of the Japanese Red Cross Society.
Customers interested in making a donation can send funds to:

•Citi Japan Disaster Relief
•Citibank Japan Ltd. (bank code: 0401, SWIFT Code for International Payments: CITIJPJT)
•Otemachi Branch (Branch #021)
•Account number: 7778563 Savings (Futsu)

*Free fund transfer if you transfer your donation from a Citibank ATM.
**Donations made to this account are not tax deductible, and we cannot provide Tax receipts. If you wish to make a donation that is eligible for a tax deduction, please donate directly to the Japan Red Cross (http://www.jrc.or.jp)

You can check it double below the URL

http://www.citibank.co.jp/en/customernotices/customernoticesindex/customernoticepages/cust_031311_01.html

Yoshi Sakai
CEO,Founder as Blueoon inc.
XOOPS Cube and LAMP Web System Developper