@blog.justoneplanet.info

日々勉強

タグに連番のidを割り振っていくJavaScript

■もったいないので載っけちゃいます

h4タグにspot+連番という形で連番のIDを振っていくJavaScriptです。ちなみにこのケースでは正規表現の後方参照でh4タグの後に数字が入っている場合のみ置換対象としています。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>無題ドキュメント</title>
<script type="text/javascript">
window.onload = function(){
	document.getElementById('execute').onclick = function(){
		var txt = document.getElementById('original').value;
		var tmpAry = txt.split(/<h4>(?=[0-9])/);
		for(var i = 1; i<(tmpAry.length); i++){
			tmpAry[i] = '<h4 id="spot' + i + '">' + tmpAry[i];
		}
		//alert(txt);
		document.getElementById('converted').value = tmpAry.join('');
	}
}
</script>
</head>
<body>
<form action="">
<textarea id="original" name="original" cols="80" rows="10"></textarea>
<textarea id="converted" name="converted" cols="80" rows="10"></textarea>
<p><input type="button" id="execute" value="execute" /></p>
</form>
</body>
</html>

■コメント

プログラムって素敵。みんなの負荷が軽くなる。自分の負荷も軽くなる。JavaScript万歳!

Dreamweaverのショートカットキー

■pタグで選択テキストを括るには

ctrl + shift + [p]

■h1~h6で選択テキストを括るには

ctrl + [1~6]

作業がガシガシ速くなる!

■ショートカットキーをカスタマイズしたいときは

スニペットの設定画面

  1. ウィンドウ > スニペット > 
  2. 右側に小窓が出るので、スニペットのフォルダの小窓で右クリック
  3. 「新規スニペット」を選択
  4. 上のような画面が出るので、スニペットに分かりやすい「名前」をつける
  5. ラジオボタンで「選択範囲を囲む」or「ブロックの挿入」を選択する

ショートカットキーの設定

ショートカットキーの設定画面

  1. ウィンドウ > スニペット > 
  2. 右側に小窓が出るので、スニペットのフォルダの小窓で右クリック
  3. 「キーボードショートカットの編集」を選択
  4. そうすると上のような画面が表示される
  5. 右側のボタンの一番左に「セットの複製」をクリック(元の設定に戻せるようにするため)
  6. 「コマンド」欄では「スニペット」を選択
  7. 上述で作った「新規スニペット」を選択
  8. 「キー」の欄をクリックし、(希望する)任意の(ショートカット)キーをキーボードでタイプ
  9. 既存のショートカットキーと重複してなければ、そのまま「OK」を押す
  10. 設定完了

※CS3オリジナルのもあるかもしれません。

Plesk内臓のphpMyAdminの文字が大き過ぎる

■書き換えるPHPファイル(基本的なCSSが分かれば書き換え可能)

/usr/local/psa/admin/htdocs/domains/databases/phpMyAdmin/css/phpmyadmin.css.php

■方法

viで書き換えるか、ダウンロードして書き換える

■今回加えたCSSコード

/********************/
/* NEW in PMA 2.7.1 */
/********************/
h2 {
	font-size: 0.9em;
}
h3 {
	font-size: 0.9em;
}
h4 {
	font-size: 0.9em;
}
li,address {
	font-size: 0.75em;
}
dt,dd,th,td {
	font-size: 0.75em;
}
p {
	font-size: 0.9em;
}
li li {
	font-size: 1em;
}
body.loginform h1,
body.loginform a.logo {
    display: block;
    text-align: center;
}

上述の4~24行目が該当のコードです。

■あとがき

てか内臓でなくても、phpMyAdminの文字サイズって大きいですよね!?表示タブを選んだときテーブルの幅が大きくなっちゃって困るんす。横スクロールしながらは非常に作業効率が悪いし。

OpenPNE3で画像がアップロード出来ない

■パーミッションの設定が間違っている

そんなときは、公開ディレクトリの「uploads」以下のパーミッションを、すべて「777」にする。


■公開ディレクトリの設定が間違っている

symfonyの公開ディレクトリの設定はデフォルトでは「web/」である。

しかし、これを理解せずに公開ディレクトリを「httpdocs/」などとしインストールを進めると、アップロードした写真が、「web/」配下に保存され、当然ながら公開ディレクトリとは異なるため、写真が表示されなくなる。

対策:symfonyにおける公開ディレクトリ名の変更

公開ディレクトリ名が「httpdocs」の場合

<?php
# FROZEN_SF_LIB_DIR: /private/tmp/symfony/lib
require_once dirname(__FILE__).'/../lib/symfony/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this->enableAllPluginsExcept(array('sfCompat10Plugin'));
    $this->setIncludePath();
  }
  public function setIncludePath()
  {
    sfToolkit::addIncludePath(array(
      //PEAR
      dirname(__FILE__).'/../lib/vendor/PEAR/',
    ));
  }
}

上述の「config/ProjectConfiguration.class.php」を以下のように変更する。

<?php
# FROZEN_SF_LIB_DIR: /private/tmp/symfony/lib
require_once dirname(__FILE__).'/../lib/symfony/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this->enableAllPluginsExcept(array('sfCompat10Plugin'));
    $this->setIncludePath();
    $this->setWebDir($this->getRootDir() . '/httpdocs');
  }
  public function setIncludePath()
  {
    sfToolkit::addIncludePath(array(
      //PEAR
      dirname(__FILE__).'/../lib/vendor/PEAR/',
    ));
  }
}

追記したのは、11行目部分の以下の記述。

$this->setWebDir($this->getRootDir() . '/httpdocs');

そして以下のコマンドでOpenPNEを再インストールする。

./symfony openpne:migrate
参考

別解:サーバ設定におけるWeb公開ディレクトリ名の変更

どちらかというと美しくない方法ではあるが、サーバ設定で変更する方法も考えられる。

DocumentRoot /var/www/vhosts/「ドメイン」/subdomains/「ドメイン」/httpdocs
<Directory  /var/www/vhosts/「ドメイン」/subdomains/「ドメイン」/httpdocs>

httpd.confやhttpd.include(Plesk)ファイルの上述の部分を以下のように編集

DocumentRoot /var/www/vhosts/「ドメイン」/subdomains/「ドメイン」/web
<Directory  /var/www/vhosts/「ドメイン」/subdomains/「ドメイン」/web>

■その他

symfony側のバグという可能性もある。

芸術的再帰

■ソース

//リストの平方和を求める関数sumOfSquares
function accumulate(combiner, nullValue, l){
    if(l.length == 0){
        return nullValue;
	}
    var first = l.shift();
    return combiner(
		first,
		accumulate(
			combiner,
			nullValue,
			l
		)
	);
}
function sumOfSquares(lst){
    return accumulate(
		function(x,y){return x*x+y},
		0,
		lst
	);
}
//sumOfSquares([1,2,3])
//14

■コメント

うーん。。。しゅごい!!!

ヌル(null)バイト攻撃を防ごう

■コレをスクリプトの先頭に書く

<?php
function removeNullBite($value){
    if(is_array($value)){
        foreach($value as $key => &$val){
            removeNullBite($val);
        }
        unset($val);
    }
    return str_replace("\0", "", $value);
}
$_GET    = removeNullBite($_GET);
$_POST   = removeNullBite($_POST);
$_COOKIE = removeNullBite($_COOKIE);
?>

■ダメージ

  • 想定外のファイルを見られる
  • 削除・書き換えをされる
  • 事前チェックを無効化される

この攻撃は他の攻撃との組み合わせで実行される事が多い。

Internet Explorer 8インストール(画面キャプチャ付き)

■まずIE8のダウンロード

http://www.microsoft.com/japan/windows/products/winfamily/ie/function/default.mspx

Internet Explorer 8がインストールできるのはWindows XP, Vista, Server2008のみだ。気になるのだがMicrosoft(マイクロソフトは)簡単に過去製品(Windows2000とか)を見捨てないであげて欲しい。サポートは長めにしてやるってのが誠意だろうに。それに古いブラウザを使ってる人が結構残ってしまうから、Web開発の立場からしても困るんです。

■さてダウンロードしたら

ダブルクリックしてインストール。するとまぁこんなのが出てくる。

インストール時の警告画面

実行をクリック

■クリックすると

インストールの開始といわれる。後で再起動が必要になるのでココで全てのアプリを終了させておく事をお勧めする。

インストールの開始

ロゴが横に潰れてるのが正直気になった(笑)。中身が潰れてなければイイが・・・

■次へをクリックすると

ライセンスの同意

当然だがライセンスには同意しなくちゃならん。同意したくないアウトローな人は諦めるべし

■同意したら

更新プログラムのインストールも勧められる。

更新プログラムのインストール

やはりセキュリティには気をつけた方がイイ世の中なのでチェックは入れておくべきだろう。

■次へを押すと

インストールが進む。んで完了。

再起動

最初に触れたが、この時点で再起動を迫られる。無理せず再起動することを勧める。

■再起動するとIE8が使えるようになる

初めての起動をすると、コンナ画面が出る

Internet Explorer 8へようこそ

こんにちは的な挨拶だ。「以前よりも早く動く」とか「アクセラレータ・・・」との事。まぁ使ってみなけりゃ分からないわな。

■次へをクリックすると

お勧めサイトを有効にする

おすすめサイト機能を有効にするか聞いてくる。面白そうなので「はい」にしてみた。どうやらユーザーの好みに応じたサイトをお勧めしてくれるらしい。

■次へいくと

設定の選択画面だ

設定の選択

細かい設定が変更できるらしいのだが時間もないので「高速設定」で今までの設定を引き継いでしまう事にする。マイクロソフトは大半のユーザーが「高速設定」を選ぶ事を知ってるはずだ。

■次はお気に入りのインポート

お気に入りのインポート

普段使ってるブラウザがIEでない人はココでチェックを入れよう。コレで設定は終わりだ!

■実際に使ってみた

実際の画面

まぁレイアウトが崩れることはない。マイクロソフトがプッシュするだけあって動きもIE7に比べたら全然滑らかである。

アクセラレータ

こんな感じでテキストを選択すると右側に半透明のアイコンが出る。

アクセラレータ

うーん便利。似たような機能は他のブラウザでも使えるが相手サイトに行かずとも翻訳が出来るのは素晴らしい。

URL蘭

アドレスバー

Google Chromeと同じように「履歴」と「検索へ」をマージして表示してくれる。

開発者ツール

開発者ツール

Firefoxは開発者に好かれてシェアを伸ばした。Microsoftはそれを学んだのだろう。

ウェブスライス(Web Slices)

一番注目されている!?機能だ。対応しているページに行くとツールバーに小さな緑色のアイコンが表示される。

ウェブスライス

クリックし購読すると、画面のようにサイトに行かなくても更新がチェックできるのだ。切り売り、まさにWeb Slicesだ。今後、IE8ユーザーが増えるにしたがってこの機能は一般的になるかもしれない。但し、今のところサイトが対応してないとスライスは出来ない。RSSに似ているが、その違いを簡単に言ってしまうと「ページの要約」と「ページの切り抜き」の違いだ。

■おまけ

タスクバー

今までIE憎しと、テストくらいにしか使ってなかったブラウザだったが、何だかタスクバーに入れてやりたい位の気持ちにはなった。常用するかどうかは今後の気分しだい。

JavaScriptの実行速度については一般ユーザーには気にならない程度になってるだろう。Firefox2では、SetTimeoutを使ったアニメーションが酷くコマ落ちしたが、あんな現象が起こらなければ、JavaScriptの速度をオレのような開発者以外が気にするような事は少ないと思う。Gmailを除けば・・・

■Firefox信者にはコチラ

FirefoxでWebSlices(microformat)には対応できないのっ!?・・・とか思ってしまった方、アドオンで実現できますよ。

PDOでSingletonを実現しよう

■はじめはコンナ感じのコードを書いてみた

class Db extends PDO {
    private static $instance;
    public function __construct($dsn, $DB_USER, $DB_PASS){
        parent::__construct($dsn, $DB_USER, $DB_PASS);
    }
    public static function getDbh(){
        if(!isset(self::$instance)){
            $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . '';
            self::$instance = new self($dsn, DB_USER, DB_PASS);
        }
        return self::$instance;
    }
    public final function __clone(){
    throw new RuntimeException('Clone is not allowed against ' . get_class($this));
    }
}
//$dbh = Db::getDbh();

普通にPDOを継承したクラスを作ってみたのだが、__constructをprivateにできない。何故なら、PDOのコンストラクタがpublicだから。この方法だとインスタンスのクローン化は防げるのだが、new演算子でDbクラスのインスタンスがいくつも作れてしまう。

■次にこんなのを書いてみた

class Db {
    private static $dbh;
    private static $instance;
    private function __construct(){
        $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . '';
        self::$dbh = new PDO($dsn, DB_USER, DB_PASS);
    }
    public static function getDbh(){
        if(!isset(self::$dbh)){
            self::$instance = new self();
        }
        return self::$dbh;
    }
}
//$dbh = Db::getDbh();

この方法だとnew演算子によるDbクラスのインスタンス化は防げる。しかしclone演算子による$dbhのクローン化を防げない。何故なら__cloneを定義しても、例外が発生するのはdbのインスタンスの複製時のみであり、dbのインスタンスとdbhは別モンだからだ。

したがって、__cloneを定義するにはclass Dbがclass PDOと同一、もしくは継承してなくてはイケナイ。

■最終的に以下のようなコードになった

final class ForbiddenClonePDO extends PDO {
    public final function __clone(){
        throw new RuntimeException('Clone is not allowed against ' . get_class($this));
    }
}
class Db {
    private static $instance;
    /**
    * constructor
    * set the instance of ForbiddenClonePDO into thie member
    */
    private function __construct(){
        try {
            $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME;
            self::$instance = new ForbiddenClonePDO($dsn, DB_USER, DB_PASS);
            self::$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);
            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        catch(PDOException $e){
        }
    }
    /**
    * get the instance of PDO
    *
    */
    public static function getDbh(){
        if(!isset(self::$instance)){
            new self();
        }
        return self::$instance;
    }
}
//$dbh = Db::getDbh();

これでdbhは単一が保障され、クローンも生成されない。ただし、個人的には新しくForbiddenClonePDOを作ってしまったのが気になる。こちらはnew演算子が使えてしまうしイマイチ美しくない。他にイイ方法があれば教えてください~!

PDOで気をつけねばならない事

■事例1

$sql="SELECT * FROM `test` LIMIT ?,?";
$stmt = $dbh->prepare($sql);
$stmt->execute(array($a, $b));

上述のように、LIMIT節にプリペアードステートメント(Prepared Statement)で値を代入しようとすると、数値がシングルクォーテーションで括られてしまい、エラーが発生してしまう。

■対策

LIMIT節にはプレイスホルダーを使わないようにする。これはPDOのバージョンによって発生したりしなかったりするので注意が必要。

■LIMIT節

基本的に数値を指定する事になると思うので、(int)を使って整数型へ変換し、数値の範囲でフィルタリングすれば、LIMIT節にプリペアードステートメントを使わなくても、SQLインジェクションは防げるはずである。