ゴミ溜め@技術系日常系雑文

主にWeb技術やそのほかつまづいたこととか引っかかって調べたこととかをまとめてます。

はてなダイアリーから引っ越しました。)

論理値へのparse、isset()、empty()、is_null()したときの戻り値

PHPで論理値へのparse、isset()、empty()、is_null()したときの戻り値をまとめてみた。
ありふれたエントリーだけど自分用のメモに。

ソース(is_.php)

<?php
$num0 = 0;
$num1 = 1;
$num1_ = -1;

$str = "";
$str0 = "0";
$str1 = "1";
$stra = "a";

$null = null;
$var;

$array = array();
$array1 = array(1);

echo "to boolean : \n";
echo "!!(\$num0)\t:\t" . var_export(!!($num0),true) . "\n";
echo "!!(\$num1)\t:\t" . var_export(!!($num1),true) . "\n";
echo "!!(\$num1_)\t:\t" . var_export(!!($num1_),true) . "\n";
echo "!!(\$str)\t:\t" . var_export(!!($str),true) . "\n";
echo "!!(\$str0)\t:\t" . var_export(!!($str0),true) . "\n";
echo "!!(\$str1)\t:\t" . var_export(!!($str1),true) . "\n";
echo "!!(\$stra)\t:\t" . var_export(!!($stra),true) . "\n";
echo "!!(\$null)\t:\t" . var_export(!!($null),true) . "\n";
echo "!!(\$var)\t:\t" . var_export(!!($var),true) . "\n";
echo "!!(\$array)\t:\t" . var_export(!!($array),true) . "\n";
echo "!!(\$array1)\t:\t" . var_export(!!($array1),true) . "\n";
echo "!!(\$array[1])\t:\t" . var_export(!!($array[1]),true) . "\n";

echo "\nisset() : \n";
echo "isset(\$num0)\t:\t" . var_export(isset($num0),true) . "\n";
echo "isset(\$num1)\t:\t" . var_export(isset($num1),true) . "\n";
echo "isset(\$num1_)\t:\t" . var_export(isset($num1_),true) . "\n";
echo "isset(\$str)\t:\t" . var_export(isset($str),true) . "\n";
echo "isset(\$str0)\t:\t" . var_export(isset($str0),true) . "\n";
echo "isset(\$str1)\t:\t" . var_export(isset($str1),true) . "\n";
echo "isset(\$stra)\t:\t" . var_export(isset($stra),true) . "\n";
echo "isset(\$null)\t:\t" . var_export(isset($null),true) . "\n";
echo "isset(\$var)\t:\t" . var_export(isset($var),true) . "\n";
echo "isset(\$array)\t:\t" . var_export(isset($array),true) . "\n";
echo "isset(\$array1)\t:\t" . var_export(isset($array1),true) . "\n";
echo "isset(\$array[1])\t:\t" . var_export(isset($array[1]),true) . "\n";

echo "\nempty() : \n";
echo "empty(\$num0)\t:\t" . var_export(empty($num0),true) . "\n";
echo "empty(\$num1)\t:\t" . var_export(empty($num1),true) . "\n";
echo "empty(\$num1_)\t:\t" . var_export(empty($num1_),true) . "\n";
echo "empty(\$str)\t:\t" . var_export(empty($str),true) . "\n";
echo "empty(\$str0)\t:\t" . var_export(empty($str0),true) . "\n";
echo "empty(\$str1)\t:\t" . var_export(empty($str1),true) . "\n";
echo "empty(\$stra)\t:\t" . var_export(empty($stra),true) . "\n";
echo "empty(\$null)\t:\t" . var_export(empty($null),true) . "\n";
echo "empty(\$var)\t:\t" . var_export(empty($var),true) . "\n";
echo "empty(\$array)\t:\t" . var_export(empty($array),true) . "\n";
echo "empty(\$array1)\t:\t" . var_export(empty($array1),true) . "\n";
echo "empty(\$array[1])\t:\t" . var_export(empty($array[1]),true) . "\n";

echo "\nis_null()\n";
echo "is_null(\$num0)\t:\t" . var_export(is_null($num0),true) . "\n";
?>

結果

pi@raspberrypi ~ $ php is_.php
to boolean :
!!($num0)       :       false
!!($num1)       :       true
!!($num1_)      :       true
!!($str)        :       false
!!($str0)       :       false
!!($str1)       :       true
!!($stra)       :       true
!!($null)       :       false
PHP Notice:  Undefined variable: var in /home/pi/is_.php on line 26
!!($var)        :       false
!!($array)      :       false
!!($array1)     :       true
PHP Notice:  Undefined offset: 1 in /home/pi/is_.php on line 29
!!($array[1])   :       false

isset() :
isset($num0)    :       true
isset($num1)    :       true
isset($num1_)   :       true
isset($str)     :       true
isset($str0)    :       true
isset($str1)    :       true
isset($stra)    :       true
isset($null)    :       false
isset($var)     :       false
isset($array)   :       true
isset($array1)  :       true
isset($array[1])        :       false

empty() :
empty($num0)    :       true
empty($num1)    :       false
empty($num1_)   :       false
empty($str)     :       true
empty($str0)    :       true
empty($str1)    :       false
empty($stra)    :       false
empty($null)    :       true
empty($var)     :       true
empty($array)   :       true
empty($array1)  :       false
empty($array[1])        :       true

is_null()
is_null($num0)  :       false
is_null($num1)  :       false
is_null($num1_) :       false
is_null($str)   :       false
is_null($str0)  :       false
is_null($str1)  :       false
is_null($stra)  :       false
is_null($null)  :       true
PHP Notice:  Undefined variable: var in /home/pi/is_.php on line 68
is_null($var)   :       true
is_null($array) :       false
is_null($array1)        :       false

警告が出てる箇所は要注意。

  1. 初期化してない変数を論理値に変換
  2. 配列に対して存在しないキーを指定して論理値に変換
  3. 初期化してない変数をis_nuill()で評価

どんなときでもとにかく変数は初期化すること!

そのほか、実現したい内容に合わせて使い分ける。

よくあるフォーカスされてるときだけ表示される検索バーの作り方

よくブログとかで画面の右上とかにある、フォーカスされてるときだけ表示される検索バーあるじゃないですか。
あれの作り方。

仕組みは簡単で、検索バーのどこかにマウスが乗ったときと、テキストフォームがフォーカスされてるときには幅などを指定して、通常時は0にしておくことで見えなくする。

DEMO

まずHTML。

<div id="search-box">
  <form action="/" id="search" name="search" method="get">
    <label id="search-label" for="search-text">サイト内検索</label>
    <input id="search-text" type="text" name="s" />
    <input id="search-submit" type="image" src="ico_search.svg" name="submit" />
  </form>
</div>

actionとかmethodとか、送信ボタンはお好みで。今回は虫眼鏡型のアイコンを送信ボタンにしてみた例。
きわめて単純。

次にスタイル定義。

/* ここら辺は見た目に関する設定。 */

input {
  line-height: normal;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

#search-box {
  position: absolute;
  top: 5px;
  right: 5px;
  height: 30px;
  overflow: hidden;
  vertical-align: top;
  border-radius: 3px;
  background: #000;
}

#search-submit {
  background: #000;
  padding: 5px;
  border-radius: 0 3px 3px 0;
  height: 30px;
  width: 30px;
  vertical-align: top;
  border: none;
}
#search-label {
  color: #fff;
  vertical-align: middle;
  padding: 0 5px;
}

#search-text {
  border: 1px solid #000;
  height: 30px;
  vertical-align: top;
  border-radius: 0;

  /* ここから下がコアな部分。 */

  /* 標準時は幅とパディング等をを0にしておくことで、表示しない。 */
  width: 0;
  padding: 0;
  margin: 0;
  
  /* アニメーションにしたければtransitionで秒数を指定する。 */
  -webkit-transition: 0.2s;
  -moz-transition: 0.2s;
  -o-transition: 0.2s;
  -ms-transition: 0.2s;
  transition: 0.2s;
}

/* フォーカスされてるときはテキストフォームの幅、パディングを指定、通常時は両方0で指定する。 */
#search-text.hover,
#search-text.focus {
  width: 400px;
  padding: 5px;
}

最後にフッター部分に、フォーカス時やホバー時、あるいはそれらが外れた時にテキストフォームのクラスを変更するためのJavaScriptを記述。

<script src="jquery.js"></script>
<script>
(function($) {

  // 検索ボタンが押された際、フォームが空欄ならテキストフォームをfocusする。
  // (空の値送信対策・スマフォ対策)
  $('#search').submit(function(){
    var $text = $('#search-text');
    if( $text.val() == '' ) {
      $text.focus();
      return false;
    }
    return true;
  });

  // ホバー時の動き。
  $('#search-box').hover(function(){
    $('#search-text').addClass('hover');
  }, function() {
    $('#search-text').removeClass('hover');
  });

  // フォーカス時の動き。
  $('#search-text').focus(function(){
    $(this).addClass('focus');
  }).blur(function(){
    $(this).removeClass('focus');
  });
})(jQuery);
</script>

以上、車輪の再発明終わり。

WordPressの Breadcrumb NavXT プラグイン(V4.3.0)プラグインでリストタグを使う

この記事はWordPressのBreadcrumb NavXT プラグイン(V4.3.0)についての記事です。

Breadcrumb NavXT プラグインは便利。
だけど、やっぱりぱんくずリストはリストタグ(<ul><li> とか、<ol><li>とか)で記述したいよねって思ったんだけど、どうにもこのプラグイン、フォーマットとして<li>タグを使うことを許してくれないらしい。
試しにGeneralの「Breadcrumb Separator」項目に

<li></li>

とか記述して変更を保存しても、見事に反映されずに空欄だけが残るという寂しいさま。

解決策としては2つ。

1つは、 Breadcrumb NavXT のソースコードを直接書き換えてしまう方法。
まあ一度書き換えてしまえばうっかりそのままプラグインをアップデートしてしまわない限り何にも考えずに思う存分LIタグを使うことが出来る。

2つめは、Separatorとして何か適当な文字列を設定しておき、呼び出すときにそれを置換する方法。
こっちだとオリジナルのソースはそのままに、機能追加だけ出来るので安全なのがメリット。

今回は、Breadcrumb Separatorに

</li><li>

と指定して、
呼び出し側のソースで

<div id="pankuzu">
<ol><li><?php bcn_display(); ?></li></ol>
</div>

としてリストを作る方法をとる。

以下、方法。

1つめ、オリジナルのソースを変更する方法

  • まず、「WPのディレクトリ\wp-content\plugins\breadcrumb-navxt\breadcrumb_navxt_class.php」の44行目付近、
  • および、「WPのディレクトリ\wp-content\plugins\breadcrumb-navxt\includes\mtekk_adminkit.php」の33行目付近の

protected $allowed_html」を書き換える。

protected $allowed_html = array(
  'a' => array(
    'href' => true,
    'title' => true,
    'class' => true,
    'id' => true,
    'media' => true,
    'dir' => true,
    'relList' => true,
    'rel' => true
  ),
  'img' => array(
    'alt' => true,
    'align' => true,
    'height' => true,
    'width' => true,
    'src' => true,
    'id' => true,
    'class' => true
  ),
  'span' => array(
    'title' => true,
    'class' => true,
    'id' => true,
    'dir' => true,
    'align' => true,
    'lang' => true,
    'xml:lang' => true
  ) /*以下を追加*/,
  'li' => array(
    'title' => true,
    'class' => true,
    'id' => true,
    'dir' => true,
    'align' => true,
    'lang' => true,
    'xml:lang' => true
  ) /*追加ここまで*/
);

書き換えて保存したら、Breadcrumb Separator項目に「<li></li>」を指定する。
スマートではある。ただしこの方法は前述の通りプラグインをアップデートしたら書き換えられてしまうのであまりおすすめできない。


次に、適当な文字列を置換する方法。
今回は、Breadcrumb Separator項目に「li/li」と記述したら

<li></li>

と置換する方法。
ぱんくずリストを呼び出すソース(header.php等)で、

<div id="pankuzu">
<ol><li><?php
if(function_exists('bcn_display')) {
	$bcn = bcn_display(true);
	echo mb_ereg_replace( "\[\[(\/?li)\]\]", "<\\1>" ,$bcn );
}
?></li></ol>
</div>

と指定。bcn_display()関数の第一引数にtrueを指定すると、勝手にechoされずに引数として文字列が渡されるので、これにたいして文字列置換をかけ、それをechoする。

あとは、Breadcrumb NavXT の設定メニューから
Breadcrumb Separator 項目に「li/li」を指定すれば完成。

オマケ。bcn_display()関数の引数:

/**
 * A wrapper for the internal function in the class
 * 
 * @param bool $return Whether to return or echo the trail. (optional)
 * @param bool $linked Whether to allow hyperlinks in the trail or not. (optional)
 * @param bool $reverse Whether to reverse the output or not. (optional)
 */
function bcn_display($return = false, $linked = true, $reverse = false){…}

第1引数・・・echoせずにreturnするか?(標準はfalse=echoする)
第2引数・・・各ノードにハイパーリンクを張るか?(標準はtrue=リンクする)
第3引数・・・ノードの並び順を逆順にするか?(標準はfalse=正順で出力)

Javascriptでブラウザ判別するスクリプト考えてみた。

車輪を再発明してみる。

発端はjQuery.browserでの判別がver1.3以降非推奨であることを知った衝撃から。
理由としてはjQuery.browserは内部的にユーザエージェントを見て判断してるから、とのこと。
じゃあCSSのベンダープレフィックス付きの要素を参照してみて有無を確かめるのはどうなの?ってことでこんなコード考えてみた。

デモページ

var browser = (function() {
	var _check= document.createElement('DIV');
	var _style = document.defaultView.getComputedStyle(_check, '');
	var _browser='msie';
	for(var s in _style ) {
		if(s==="webkitTransform") {
			_browser = 'webkit'; break;
		}
		if(s==="MozTransform") {
			_browser='firefox'; break;
		}
		if(s==="OTransform") {
			_browser='opera'; break;
		}
	}
	return _browser;
})();
console.log( 'your browser is ' +browser );

例ではCSS3のtransformを使ってみた。
各ブラウザは、ドラフト段階のCSSを先行採用した際の名残として、ベンダープレフィックス付きのスタイル定義がある。(例:Firefoxであれば「-moz-transform」など。javascriptで参照する際は「style.MozTransform」)
そこで、document.createElement()で生成した空のDIV要素に対してgetComputedStyleして取得したスタイル定義一覧に、各ブラウザ固有のベンダープレフィックス付きのスタイルが定義されているか否かを基準に判断してしまおう、という考え。

IEはそもそも「document.defaultView.getComputedStyle」をサポートしてないので、どの条件式にもヒットしなければIEでいいや、という動き。

今後各ベンダがプレフィックス付きのスタイルを廃止したら(あるいはOperaのように他ベンダのプレフィックスをサポートしたら)誤判断してしまう問題があるので、実際に使用する際にはもう少し対応が必要かも。

Sleipnir For Android / Dropbox内の"Apps\Fenrir Pass Connect\.dropbox"ファイル?

Sleipnir For Android を使用してて、なにやらDropbox内に勝手に(?)ファイルが作成されてたので何なのかFenrirに問い合わせてみた。


件名

【ご質問】Sleipnir For Android / Dropbox内の"Apps\Fenrir Pass Connect\.dropbox"ファイル?

本文

平素よりお世話になります。
○○○○ と申します。

御社の「Sleipnir Mobile For Android」を使用しております。

(1)お名前
○○○○

(2)クライアント情報
端末: au/Samsung GALAXY S2 WiMAX(非root)
Sleipnir Mobile For Android 2.2.2

(3)ウイルス対策ソフト / ファイアウォールソフト
Zoner AntiVirus

(4)常駐させているソフトウェア(影響を与えそうなもの)
Dropbox

(5)お問い合わせの種類(質問、不具合報告など)
Dropbox内に作成された不明なファイルについて

(6)症状の詳細
Dropboxフォルダ内を確認してみましたところ、知らない間に
 "\Apps\Fenrir Pass Connect" フォルダ
が作成され、フォルダ内に ".dropbox" という不明なファイルが作成されていたため、こちらの詳細を伺いたく問い合わせした次第です。

おそらくその名の通り、Fenrir Pass Connectの認証用ファイルか何かかとは存じますが、念のため。


以上、ご回答いただければ幸いです。
よろしくお願いします。

* いまさら名前を伏せ字にしてもしょうがない気もするけど。

回答待ち、なう。

16進カラーコードまたは色名を10進に変換するjavascriptコード。

Web Color 以外の色 - 色名指定が可能な色の見本をもとに、16進カラーコードまたは色名を10進に変換するjavascriptコードを書いた。

String.prototype.toDecColorCode || (function(){

  var name = {
    white                : { red : 255 , green : 255 , blue : 255 }, 
    /* 〜以下、名前指定できる色一覧〜 */
  };
  
  function range( value, minimum, maximum ) {
    if( value > maximum ) return maximum;
    else if( value < minimum ) return minimum;
    return value;
  }
  
  String.prototype.toDecColorCode = (function(){
    var str = (this+'').toLowerCase().replace(/#/,'');
    
    if( /^[0-9a-fA-F]{3}$/.test(str) ) {
      return {
        red   : parseInt( str.charAt(0) + str.charAt(0), 16 ),
        green : parseInt( str.charAt(1) + str.charAt(1), 16 ),
        blue  : parseInt( str.charAt(2) + str.charAt(2), 16 ),
        alpha : 0
      };
    }
    else if( /^[0-9a-fA-F]{6}$/.test(str) ) {
      return {
        red   : parseInt( str.substr(0,2), 16 ),
        green : parseInt( str.substr(2,2), 16 ),
        blue  : parseInt( str.substr(4,2), 16 ),
        alpha : 0
      };
    }
    else if( str.match(/([0-9]{1,3})[^0-9]*([0-9]{1,3})[^0-9]*([0-9]{1,3})[^0-9.]*([0-1]?.?[0-9]{1,})/) ) {
      return {
        red   : range( parseInt(RegExp.$1,10), 0, 255 ),
        green : range( parseInt(RegExp.$2,10), 0, 255 ),
        blue  : range( parseInt(RegExp.$3,10), 0, 255 ),
        alpha : range( parseFloat('0'+RegExp.$4,10), 0, 1 )
      };
    }
    else if( str.match(/([0-9]{1,3})[^0-9]*([0-9]{1,3})[^0-9]*([0-9]{1,3})/) ) {
      return {
        red   : range( parseInt(RegExp.$1,10), 0, 255 ),
        green : range( parseInt(RegExp.$2,10), 0, 255 ),
        blue  : range( parseInt(RegExp.$3,10), 0, 255 )
      };
    }
    else {
      
      for( n in name ) if( str == n ) return name[n];
      
      return '';
    }
  });
})();

全文 toDecColorCode.js

使い方

// color1,color2,color3,color4はいづれも、{ red: 0, green: 0, blue: 0 }となる。
var color1 = toDecColorCode( "black" );
var color2 = toDecColorCode( "#000" );
var color3 = toDecColorCode( "#000000" );
var color4 = toDecColorCode( "rgb(0,0,0)" );

// アルファチャンネルが指定されている場合はアルファチャンネルも返す。
var color5 = toDecColorCode( "rgba(0,0,0,0.5)" );
  // color5 = { red: 0, green: 0, blue: 0, alpha: 0.5 }

応用:
例えば、下記のような構成があったとする。

/* style.css */
#foo { background: #000; }
<html>
  <head>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <p id="foo">text</p>
  </body>
</html>

要素fooの文字色に背景色の反対色を設定したいとする。
背景色の取得は下記のようにできる。

// 外部スタイルシート反映済みの完全なスタイル設定を取得するコード。
var getStyle = (function(target, cssProperty){
  var style = target.currentStyle || document.defaultView.getComputedStyle(target, '');
  return style[cssProperty];
});

// 背景色を取得。
var target = document.getElementById('foo');
var bg = getStyle( target, "backgroundColor" );

しかし、せっかく取得した背景色bgの値はブラウザによって変わってくる。
例えば、Firefoxであれば「"rgb(0, 0, 0)"」、IEであれば「"#000"」となる。
ここで、

// 背景色を取得。
var bg = getStyle( target, "backgroundColor" );
bg = target_bgcolor.toDecColorCode();

とすると、target_bgcolorはかならず「{ red:0, green:0, blue:0 }」となる。
文字色に反対色を設定するならば、

// 背景色を取得。
var bg = getStyle( target, "backgroundColor" );
bg = bg.toDecColorCode();

// 反対色を生成。
var color = "rgb("+ 
                (255-bg.red  ) +","+
                (255-bg.green) +","+
                (255-bg.blue ) +")";

// 設定。
target.style.color = color;

サンプルコード

洗練さにかけるけどとりあえず動くからよし。
そのうち直す。

備考録。ユーザーエージェントで処理を分ける。

備考録。
ユーザーエージェントからブラウザ、ブラウザバージョンを特定し、スマフォであれば$is_mobileをtrueにするPHPコード。

<?php
// ユーザーエージェントは下記が参考になる。
// http://www.openspc2.org/userAgent/

// ユーザーエージェントの取得。
$ua = $_SERVER['HTTP_USER_AGENT'];

$browser = 'Unknown';
$version = 0;
$is_mobile = false;

// ブラウザの判別。
if( preg_match("/(MSIE|Chrome|Firefox|Android|Safari|Opera)[\/ ]([0-9.]*)/", $ua, $match ) ) {
  $browser = $match[1];
  $version = explode( ".", $match[2] );
    // ブラウザバージョンはドット区切りで配列として格納。
    // (メジャーバージョンの数値の大小で比較し安くするため。)
}

// デバイスがモバイル端末であるか判別。(タブレットは除く。)
if( preg_match("/(iPhone|iPod|Windows Phone|Opera Mobi|Fennec|Android)/",$ua, $match ) ) {
  // Opera MobiはAndroid版Opera、FennecはAndroid版Firefox。
  // なお、UA文字列中の"Opera Mobi""Fennec"という文字列は"Android"より後に記述されているので、
  // 比較する順序に注意する。
  // ex.
  //   Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; ja) Presto/2.9.201 Version/11.50
  //   Mozilla/5.0 (Android; Linux armv7l; rv:9.0) Gecko/20111216 Firefox/9.0 Fennec/9.0
  
  // Androidであり、Mobileを含まない場合は除外。
  // 標準のAndroidブラウザの場合、UAにMobileという文字列を含むので、
  // これの有無によってタブレットかスマフォかを判断する。
  if( !( $match[1] == "Android" && !preg_match("/Mobile/",$ua) ) ) {
    $is_mobile = true;
  }
}
?>

HTMLで出力してみるには

<!DOCTYPE html>
<html><head><meta charset="UTF-8">
<title>ユーザーエージェントを判別する。</title></head><body>

<p>User Agent: <?=$ua?></p>
<p>あなたのブラウザは 
<?=$browser?>                                   <!-- ブラウザ名を表示 -->          
<?=implode(".",$version)?>                      <!-- ブラウザバージョンをドット区切りで表示 -->
( <?= $is_mobile ? "mobile" : "not mobile" ?> ) <!-- モバイルか否かを表示 -->
</p>

</body></html>

なんにせよ、ユーザーエージェントはバージョンが変わると書式が変わる可能性もある不確かなものなので、厳密な判別には使えない。
主にモバイル用とPC・タブレット用でCSSを変更するとか、とか。