
function &queryF($sql, $limit=0, $start=0)
{
// add read only mode
$sql = ltrim($sql);
$sql_parts = explode(' ', $sql);
$first_part = strtolower(trim($sql_parts[0]));
if (!preg_match('/^(\/\*|select)/', $first_part )){
if($first_part == 'insert' || $first_part == 'delete'){
$table_part = trim($sql_parts[2]);
}else{
$table_part = trim($sql_parts[1]);
}
preg_match('/^`?'.XOOPS_DB_PREFIX.'_([^`].+)`?/', $table_part, $match);
$table_name = $match[1];
if($table_name == 'session'){
$is_safe = true;
}else{
$is_safe = false;
}
if($is_safe == false){
$ret = false;
return $ret;
}
}
このハックを適用すると、




テンプレートの使いこなしテクニックを紹介します。 やや上級向けですが、ぜひ見てください。
カスタマイズの例として、2つ取り上げます。
今回ここで紹介する手法を使わなくても、いくつか別の方法で同じようなことができます。 それに対してpicoを活用する方法によるメリットを、挙げてみましょう。
このうち権限管理は、主にサイト管理やコンテンツ管理を複数人で行う場合の利点です。
コンテンツのパーツを、picoのあるカテゴリにまとめておきます。 すると「カテゴリーアクセス権限」で特定のグループやユーザーに、編集権限を設定することもできます。 モジュールの管理者権限を渡さずに、つまり管理者メニューにアクセスできなくても、コンテンツを管理できるのです。
カスタマイズの肝になるのは、「xugj_block」の利用です。 xugj_blockについての詳しい説明は今回の趣旨とは外れますが、簡単に言うと「ブロックを自在に表示できるようになるSmartyプラグイン」です。 ただしXOOPSの標準的な機能ではなく、プラグインを追加する必要があります。
といった部分を編集する際に使えます。
SourceForge.net function.xugj_block.php
上記のリンクからダウンロードできるほか、ホダ塾ディストリビューションであれば含まれていますので、追加インストールの必要はありません。
自分でインストールする場合は、 xoops_trust_path/libs/smartyplugins/function.xugj_block.php もしくは html/class/smarty/plugins/function.xugj_block.php に配置します。作業前の時点でxoops_trust_path/libsが空であるなら、html/class/smarty/plugins/を使った方が手軽でしょう。
xugj_blockは非常に「使い出」があり、オプションなどの記述もかなり複雑です。 使うたびに長い記述をするのはミスを招きます。 そのため今回は、「カスタムテンプレート」を使って、簡単に書けるようにします。
<{xugj_block func="b_pico_content_show" options="pico|12||1" file="/modules/pico/blocks/blocks.php"}>
このような記述をするところを、picoのdirnameが標準的な「pico」であるならば、最低限度として、content_idだけ指定すれば動きます。
<{include file="db:_custom_xugj_block_pico.html" content_id="12"}>
こうなります。「db:_custom_xugj_block_pico.html」部分は固定ですので、最後の数字だけ変えればいいことが解かります。
カスタムテンプレートというものが出てきました。 これはALTSYSモジュールを使って作成します。
今回はテンプレート名「_custom_xugj_block_pico.html」として説明します。 実際にはファイルではなく、データベース内にのみ作成されます。なのでファイルを探してもありません。
作成するときは「新規カスタムテンプレート作成」リンクを、既に作成済のテンプレートを編集する場合は、「編集」リンクです。
<{* xugj_block pico.content_block ここから *}>
<{assign var="picoDirname" value=$picoDirname|default:"pico"}>
<{assign var="content_id" value=$content_id|default:"1"}>
<{assign var="this_template" value=$this_template|default:""}>
<{assign var="process_body_yes" value=$process_body_yes|default:"1"}>
<{capture assign="xugj_block_options"}><{strip}>
<{$picoDirname}>|<{$content_id}>|<{$this_template}>|<{$process_body_yes}>
<{/strip}><{/capture}>
<{capture assign="xugj_block_file"}><{strip}>
/modules/<{$picoDirname}>/blocks/blocks.php
<{/strip}><{/capture}>
<{xugj_block func="b_pico_content_show" options=$xugj_block_options file=$xugj_block_file}>
<{* xugj_block pico.content_block ここまで *}>
ここまででまだ、準備も半ばです。
次に、コンテンツの「パーツ」を作成します。
「サイトのヘッダー部分」「D3ブログで、常に表示するコンテンツ」の2つです。
picoの扱いに付いては説明を省きます。 うさぎにもできるXOOPS Cube入門♪ - モジュールを使おうpico編を参考にしてください。
注意点として、オプションで「表示」のチェックを付けてください。 これを忘れると、ゲスト(ログイン前の状態)に対して正常な表示ができません。 ほかに適宜、アクセス権現の設定を見直してください。ゲストにpicoモジュールのアクセスを許可する必要があります。
そして次に、テーマの編集です。 「default」テーマを使っていて、またDBテーマ編集モジュールを使う場合の例を挙げますが、ここは特に決まりはなく、基本的にどのテーマでも可能ですし、直接テーマ・ファイルを修正しても構いません。(その方が手順はシンプルになるかもしれません。)
次にD3ブログのテンプレートを修正します。 修正するテンプレート名は「d3blog_inc_header.html」です。(d3blogというdirnameでインストールしている場合)
以上で修正箇所は終わりです。
最後に、プラスαの技を紹介します。 pico側で作成したコンテンツを全て表示する替わりに、「続きを読む」形式で省略表示する方法です。
次の内容でカスタムテンプレートを作成(_custom_pico_short)し、
<{include file="db:_custom_pico_short" content_id="12" truncate_num="100"}>
のように呼び出して使います。
<{* xugj_block pico.content_block ここから *}>
<{assign var="picoDirname" value=$picoDirname|default:"pico"}>
<{assign var="content_id" value=$content_id|default:"1"}>
<{assign var="this_template" value=$this_template|default:""}>
<{assign var="process_body_yes" value=$process_body_yes|default:"1"}>
<{assign var="truncate_num" value=$truncate_num|default:"30"}>
<{capture assign="xugj_block_options"}><{strip}>
<{$picoDirname}>|<{$content_id}>|<{$this_template}>|<{$process_body_yes}>
<{/strip}><{/capture}>
<{capture assign="xugj_block_file"}><{strip}>
/modules/<{$picoDirname}>/blocks/blocks.php
<{/strip}><{/capture}>
<{xugj_block item="xugj_block_pico" func="b_pico_content_show" options=$xugj_block_options file=$xugj_block_file}>
<{$xugj_block_pico.content.body|mb_truncate:$truncate_num}>
<a href="<{$xugj_block_pico.mod_url}>/<{$xugj_block_pico.content.link}>">続きを読む</a>
<{* xugj_block pico.content_block ここまで *}>
]]>if (extension_loaded('wincache') === true) {
ini_set('wincache.fcenabled', 0);
ini_set('wincache.ocenabled', 0);
}をmainfile.phpの最初に記述すると良いようです。FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Save','NewPage','Preview','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Form','Checkbox','Radio','TextField','Textarea','Select','Button','ImageButton','HiddenField'],
'/',
['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent','Blockquote'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
'/',
['Style','FontFormat','FontName','FontSize'],
['TextColor','BGColor'],
['FitWindow','ShowBlocks','-','About'] // No comma for the last row.
] ;
の部分を書き換えて変更できます。FCKConfig.ToolbarSets["Default"] = [
['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
'/',
['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent','Blockquote'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
'/',
['Link','Unlink','Anchor'],
['Image','Smiley','PageBreak'],
['TextColor','BGColor'],
] ;
こんな感じになります。FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/default/' ;
の部分を変更することで3種類のスキンから選ぶことが出来ます。FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/office2003/' ;
FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/silver/' ;
Shioriモジュールを使ってみることにしました。
それで簡単な説明と、気づいた点を書いていこうと思います。
いわゆるXOOPS2時代に開発されていた、栞(最終バージョン 0.51)の後継版です。 すっかり作り替えたそうです。
PHPのバージョンがある程度より古いと、動作しない(サポート外)ようです。 PHP 5.2.4 以上 (mbstring 必須)。
Shiori 1.02 | スイナシア (説明、 「shiori」なエントリー)
さっそく付属の説明書を確認しました。
readme_ja.html という名前のファイルです。 配布元のサイト以上に、詳しいことが書いてあるようです。 以後はこれを読んで、その内容のまま進めてみます。
インストール手順はごくオーソドックスで、モジュールのインストールに慣れた方であれば、悩むことはないでしょう。 そのあたりはちょと端折って説明します。
インストールの最初は、サーバーにファイルを配置しました。
管理画面の「モジュールのインストール」で、インストールしました。
また説明の通りに、ブロックのインストールと権限の設定もしました。
ここまでで、基本的な機能が使えるようになりました。
Shioriモジュールのワンクリックブックマーク機能 | スイナシア
★型のアイコンをクリックすると、そのアイコンがくるくる回る画像になって、ブックマークできる様子が見えます。 これに挑戦しました。
説明書の通りに、ユーザーメニューを修正しました。
詳しいことは省きますが、残念ながらこれだけでは、動画のような動きにはなりませんでした。
スタイルシートで非表示になっているので、それを解除します。
修正するファイル 互換モジュール
legacy_block_usermenu.html
<a href="<{$xoops_url}>/modules/shiori/"><img src="<{$xoops_url}>/modules/shiori/images/unbookmarked.png" id="shiori_bookmark_star" style="float:right;display:none;" rel="<{$xoops_url}>" />Bookmark</a>
<a href="<{$xoops_url}>/modules/shiori/"><img src="<{$xoops_url}>/modules/shiori/images/unbookmarked.png" id="shiori_bookmark_star" style="float:right;" rel="<{$xoops_url}>" />Bookmark</a>
大抵のケースでは、テンプレートの修正はALTSYSを使うと便利です。 管理者メニューから、書き換えたいテンプレートを編集できます。
しかし使っているテーマによっては、その方法が通用しません。 「hd_default」がこれに該当します。 「テーマ下テンプレート」と言われる仕組みでテンプレートを管理しているので、それを書き換える必要があるのです。
しかも、全てのテンプレートがテーマ下テンプレートになる訳ではなくて、hd_defaultに同梱されていた(+自身で追加した)テンプレートだけがそのようになります。 この条件に合ってないテンプレートは、いつものように、ALTSYSで編集できます。
修正するファイル
html/themes/hd_default/templates/legacy_block_usermenu.html
これは、大抵のひとには問題にならないと思われます。
問題となるのは、サーバーの中でZIPファイルを直接展開しているなどで、 ZIPファイルが作成された時のパーミッションをそのまま引き継いだ場合です。
これを修正しました。
html/modules/shiori/images/ の中の画像ファイルは全て、「644」にします。
ブックマークには名前(ページ名)が付くのですが、それにサイト名も一緒に入っていて、これは変えたいと思いました。 どうやらこの文字列は、title要素のテキスト(ブラウザのタイトルバーに表示されている)が使われるようです。
この部分はテンプレートの修正で対応可能です。 こちらはALTSYSで編集しました。
管理者メニューでALTSYSの管理画面を開き、さらに「テンプレートの管理」というサブメニューを辿って、Shioriモジュールのテンプレートを見付けます。
修正するテンプレート Shioriモジュール
shiori_block_bookmark.tpl
document.write('<input type="hidden" name="title" value="' + document.title + '" />');
document.write('<input type="hidden" name="title" value="' + document.title.replace('XOOPS Cube Site - ', '') + '" />');
「XOOPS Cube Site - 」の部分は、サイト名+「(スペース)(マイナス)(スペース)」です。 もしこのブログ記事を読んで同じことする場合は、各自のサイトで使っているサイト名を当てはめます。 これで、サイト内のブックマークではサイト名が付かないようになりました。
おまけです。
「ブックマークの最大保存件数」は、各ユーザーが一人でブックマークできる件数でした。
「1ページ当たりに表示するブックマークの件数」は、Shioriの画面でブックマーク一覧を見るとき、に使われる設定になっています。
以上です。
]]>find . -type f | nkf -w --overwrite
で変換できます。











<img src="<{$block.uid|ryus_user_rank}>" title="<{$block.uid|ryus_user_rank:"title"}>" />
<{$block.uid|ryus_user_rank}> あるいは <{$block.uid|ryus_user_rank:"image"}> で画像URL
<{$block.uid|ryus_user_rank:"title"}> でランク名
を表示するだけです。
<script>
var db = openDatabase("sample", "1.0", "Sample database", 1024 * 1024);
function createTable() {
db.transaction(function(tx) {
tx.executeSql(
"CREATE TABLE IF NOT EXISTS users( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(64) NOT NULL);",
null,
insertData,
function() {
alert("CREATE 失敗");
}
);
});
}
function insertData(tx) {
tx.executeSql(
"INSERT INTO users(name) VALUES(?);",
["hamaco"],
findData,
function() {
alert("INSERT 失敗");
}
);
}
function findData(tx, rs) {
tx.executeSql(
"SELECT * from users WHERE id = ?",
[rs.insertId],
function(tx, rs) {
document.body.innerHTML = rs.rows.item(0)["name"];
},
function() {
alert("SELECT 失敗");
}
);
}
createTable();
</script>
開発では、なにごともやってみて初めて分かるということがあるものです。 今回は、あるコンテンツに対して「HEADリクエストを送って存在確認をする」、というスクリプトを(PHPで)書いた時の話です。
マニュアルにはレスポンスが正常な場合(200 OK)の例が掲載されています。 これが、リダイレクトするコンテンツの場合には、少々様子が異なってきます。
結果を書いてしまうと、「get_headers()はリダイレクトを辿って複数のリクエストを行う」ということを知りました。 私は「HTTP HEADの結果に係わらず、1回だけリクエストして、その結果を返す」という動作を(勝手に)想像していたのですが、違いました。
動作を確認するために以下のような、リダイレクトを数回繰り返すサンプルを用意しました。(redirect.php)
<?php
$req = $res = $_SERVER['REQUEST_URI'];
if (preg_match('/[^\w\:\/\.]/i', $req)) {
echo 'wrong request.';
} else {
if (strpos($req, '.php') === (strlen($req) - 4)) {
$res = $res . '/';
}
if (!strpos($req, '1111')) {
$res = $res . '1';
header('Location: ' . $res);
} else {
echo htmlspecialchars($req, ENT_QUOTES, 'UTF-8');
}
}
これを、get_headers()を使って結果を見ます。(別のスクリプトです)
<?php
var_dump(get_headers('http://localhost/redirect.php', 1));
その結果が以下になります。
※分かりやすくするために、一部を編集しました
array
0 => string 'HTTP/1.1 302 Found' (length=18)
1 => string 'HTTP/1.1 302 Found' (length=18)
2 => string 'HTTP/1.1 302 Found' (length=18)
3 => string 'HTTP/1.1 302 Found' (length=18)
4 => string 'HTTP/1.1 200 OK' (length=15)
'Date' =>
array
0 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29)
1 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29)
2 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29)
3 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29)
4 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29)
'Server' =>
array
0 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx)
1 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx)
2 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx)
3 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx)
4 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx)
'X-Powered-By' =>
array
0 => string 'PHP/5.2.4-2ubuntu5.7' (length=20)
1 => string 'PHP/5.2.4-2ubuntu5.7' (length=20)
2 => string 'PHP/5.2.4-2ubuntu5.7' (length=20)
3 => string 'PHP/5.2.4-2ubuntu5.7' (length=20)
4 => string 'PHP/5.2.4-2ubuntu5.7' (length=20)
'Location' =>
array
0 => string '/redirect.php/1' (length=15)
1 => string '/redirect.php/11' (length=16)
2 => string '/redirect.php/111' (length=17)
3 => string '/redirect.php/1111' (length=18)
'Content-Length' =>
array
0 => string '0' (length=1)
1 => string '0' (length=1)
2 => string '0' (length=1)
3 => string '0' (length=1)
4 => string '18' (length=2)
'Connection' =>
array
0 => string 'close' (length=5)
1 => string 'close' (length=5)
2 => string 'close' (length=5)
3 => string 'close' (length=5)
4 => string 'close' (length=5)
'Content-Type' =>
array
0 => string 'text/html' (length=9)
1 => string 'text/html' (length=9)
2 => string 'text/html' (length=9)
3 => string 'text/html' (length=9)
4 => string 'text/html' (length=9)
get_headers()の第2引数に「1」をセットしなかった場合は、もっと混沌とした結果になっていましたが、省略します。
それと今回は、自分自身にリダイレクトするスクリプトで実験しました。 異なるサーバ/スクリプトに跨ってリダイレクトを辿った場合は、レスポンス・ヘッダーの内容も異なると思われますので、もう少し複雑な結果になります。
これを受けて、「Locationの結果、行き着くコンテンツ」は次のように取得できることがわかります。 ただし、URLの解決(絶対URLに直す処理)は端折っています。 あと実際のコードでは、エラー処理など適宜しています。
<?php
$url = 'http://localhost/redirect.php';
$headers = get_headers($url, 1);
$location = $headers['Location'];
if (is_array($location)) {
$location = array_pop($location);
}
if (
(strpos('/', $location) === false)
and
(strpos('http', $location) === false)
) {
$location = dirname($url) . '/' . $location;
}
echo "original: {$url} \n redirected: {$location} \n";
以上です。
]]>
