スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[PHP] XOR でビット演算させようとして、AND とか OR と同じような動きにならないんだけど変くね?

なんか根本的におかしなことをやっている可能性もあるのですが、
XORで計算する必要がありまして、AND とか OR みたいに扱えるかと
思ったらそうでもなかった、という話。

結局はベタな関数を自作してなんとか対処したのですが、
下記のような感じ。


<?php
//========================================
// 文字列全体をXORマスク
//========================================

function ProcXor( $str, $str2 ){
$ret = "";
//適度にエラーチェック
if( ( strlen( $str ) < 0 ) || ( strlen( $str ) < 0 ) ){
return( $ret );
}elseif( ( strlen( $str ) != strlen( $str ) ) ){
return( $ret );
}
//1文字ずつ XORして結果を文字で返す
for( $i = 0; $i < strlen( $str ); $i++ ){
$c = substr( $str, $i, 1 );
$c2 = substr( $str2, $i, 1 );
$ret .= ( $c xor $c2 ) == 1 ? "1" : "0";
}
return( $ret );
}

//========================================
// メイン
//========================================

$buf = "";
$a = bindec( '10101111' );
$b = bindec( '11111111' );

$buf .= "A:".decbin( $a )."<br />\n";
$buf .= "B:".decbin( $b )."<br />\n";
$buf .= "<hr />";

$c = $a & $b;
$buf .= "A AND B : ".decbin( $c );
$buf .= "<br />\n";
$c = $a | $b;
$buf .= "A OR B : ".decbin( $c );
$buf .= "<br />\n";
$c = $a xor $b;
$buf .= "A XOR B : ".decbin( $c );
$buf .= "<br />\n";
//追記 2010.08.19
$c = $a ^ $b;
$buf .= "A XOR B (^) : ".decbin( $c );
$buf .= "<br />\n";

//追記 2010.08.19 ここまで
$c = ProcXor( decbin( $a ), decbin( $b ) );
$buf .= "A XOR B (2) : ".$c;
$buf .="<br />\n";

include( 'mask.tmpl' );
?>



A として 10101111
B として 11111111

という値を用意して、AND、OR、XOR をかけてみると。

結果は上のとおりで、AND、OR は期待通りの値になるのですが、XOR だけうまくいかない。
排他的論理和ですから、異なってるときだけ真になって、01010000 となるのが正解のはずが、
$a xor $b だと 10101111 とかいう OR と同じ結果を返してくる。

2進10進の値の取り扱いに問題があるのかと思ったのですが、それにしたところで
AND や OR と同じような動きをしてくれないのは具合が悪い。
というわけで、1文字ずつ XOR をかけて(これは正常に見える)その結果を文字列として
重ねていくという変なことをしています。こうすると期待した結果になりました。

2010.08.19 追記

私がへっぽこでした!

下記コメントいただいたように、「xor」は論理演算子で、
ビット演算をさせたいときには「^」のビット演算子を使用すべきでした。

論理演算子
http://php.net/manual/ja/language.operators.logical.php

ビット演算子
http://php.net/manual/ja/language.operators.bitwise.php

というわけで、前述の内容も追記修正しました。ビット演算子「^」を使った
部分はちゃんと計算されてますね。

珍妙自作関数なんかいらんかったんや!

テーマ : PHP
ジャンル : コンピュータ

タグ : PHP

[PHP] $_SESSION が急に効かなくなった? サーバの一時ファイルの容量が問題かも

タイトルでほぼ結論書いてしまってるのですが、
事象としては、とあるシステムのログインが効かなくなったと。
具体的な動きとしては、ログインの認証は成功するのでデータベースまわりは
問題ないけれど、ログイン後に遷移しているページでそのログイン情報を確認できず
(つまりは $_SESSION['xxxx'] の中身が空)、ログインページに戻されるというもの。

なんやらかんやら試してみて、
php.ini でセッションを管理するためのファイルを保存する場所の設定
session.save-path などをどこか任意に作った書き込みOKの場所に設定してみると
ちゃんとセッションファイルもできてるし、ログインも正常に行ったりします。
他にも検証しているとファイルのアップロードも失敗して、これもどうやらサーバの
一時領域への保存に失敗しているのではないかと思われました。

このときはログを見ることを失念していたのですが、どうやら
PHP Warning: Unknown(): write failed: Disk quota exceeded
というエラーログが吐かれていた模様。この事象が出たのは共有サーバで、
割り当てられているHDD容量的にはスカスカで問題がなかったものの、
共有サーバで用いている一時ファイルのディレクトリが、サーバ会社側で割り当てた
容量を越えているとの指摘をサーバ会社から受けました。

その一時領域はFTPからは確認できないものの、スクリプトを介して
確認してみると、何か巨大なファイルがあるのを確認しました。
ファイル名からしてどうやら ImageMagick という画像処理のソフトウェアがつくった
ものらしいのですが、なぜそんな巨大なファイルができているのかは不明。

内容を確認してもただ空のファイルで問題ないと思われたのでスクリプトを介して削除。
そうすると問題なく動作するようになりましたとさというお話。

テーマ : PHP
ジャンル : コンピュータ

[PHP] $_SERVER['HTTP_ACCEPT_LANGUAGE'] からの言語設定の取得

ブラウザの言語設定をPHPで取得してあれやこれやするための前準備として。
具体的には英語圏からのアクセスは英語ページへ、などという用途があるかと思います。




ブラウザの言語設定は $_SERVER['HTTP_ACCEPT_LANGUAGE'] で取ることが出来ます。
内容としては上記サンプルの1行目のように、ja,en-us;q=0.7,en;q=0.3 みたいな形の文字列です。

[言語],[言語];q=[優先度],[言語];q=[優先度],[言語];q=[優先度]...
の並びの文字列なので、欲しい情報は得られていますが、あれこれするためには
配列か何かに展開すればいいでしょう。まず "," 、次に ";" で explode() すれば、
二次元の配列に整理できるはずです。

そのあとは、言語設定にXXXが含まれているか? 何が言語設定で最優先か? などは
配列を走査すればわかりますね。

上記のサンプルのソースはこんな感じ。

<?php
//言語設定リストの取得
$lang_list = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : "";

$buf = "HTTP_ACCEPT_LANGUAGE : ".$lang_list;
$buf .= "<br />";

//まずカンマで分解
$ary_lang = explode( ",", $lang_list );

//処理しやすいように配列に展開
$ary_lang_rate = array("");
for( $i = 0; $i < count( $ary_lang ); $i++ ){
//セミコロンで分解
$temp = explode( ";", $ary_lang[$i] );
//最優先は数値がついていない
if( count( $temp ) > 1 ){
$ary_lang_rate[$i]['lang'] = trim( $temp[0] );
$ary_lang_rate[$i]['rate'] = trim( str_replace( "q=", "", $temp[1] ) );
}else{
$ary_lang_rate[$i]['lang'] = $ary_lang[$i];
$ary_lang_rate[$i]['rate'] = 1;
}
}

//配列を出力してみる
for( $i = 0; $i < count( $ary_lang_rate ); $i++ ){
$buf .= $ary_lang_rate[$i]['lang'];
$buf .= " : ";
$buf .= $ary_lang_rate[$i]['rate'];
$buf .= "<br />";
}
include( "lang.tmpl" );
?>

テーマ : PHP
ジャンル : コンピュータ

[PHP] Content-Disposition: attachment; でファイルを出力したら古いInternetExplorer(IE6など)で「この文書を開くときにエラーが発生しました」と表示されるでござる

ファイルをダウンロードさせるとき、ヘッダを Content-Disposition: attachment; とか
打ってやって、読んだファイルの内容を続けて出力させて、ということをやりますよね。

PHPでファイルをDLさせる際のPHPコード例
http://phpspot.org/blog/archives/2008/02/phpdlphp.html

例)
$len = filesize( $file );
header( 'Content-Type: application/octet-stream' );
header( 'Content-Disposition: attachment; filename="'.$file.'"' );
header( 'Content-Length: '.$len );
readfile( $file );

たいていは機嫌よくダイアログが出てくれて、開くか保存を選ぶようになって、
開くならアプリケーションでファイルを開くし、保存ならさらに保存ダイアログが
開いたり。

でも、古い Internet Explorer を使うと、「開く」を選んだときに
「ファイルが見つかりません」であるとか、「ファイルを開く際にエラーが発生しました」
など言われてしまいます。これはマイクロソフトの方でも情報を公開していて、

Content-Disposition: attachemnt と Cache-Control: no-cache によるダウンロードの問題
http://support.microsoft.com/default.aspx?scid=kb;ja;436605

Internet Explorer を使用して下記条件を満たすファイルを開いた場合、ファイル名が見つからない内容のエラーが発生し、ファイルを開くことができない場合があります。

* ダウンロード対象となるファイルに Content-Disposition:attachment ヘッダーを付加している
* Cache-Control:no-cache ヘッダーなどを使用して、ファイルのキャッシュを行わない設定をしている

弊社では、 TXT ファイル、DOC ファイル、CSV ファイル、XLS ファイル、PPT ファイル、PDF ファイル等のファイルでこの現象の発生を確認しております。
上記条件を満たすファイルへのリンクをクリックした場合、[ファイルのダウンロード] ダイアログが表示されます。
この時、[開く] および [保存] を選択しサンプル ファイルを開こうとすると、ファイルが見つからない内容のエラーが発生します。
尚、この際に表示されるエラーメッセージは関連付けられたアプリケーションによってことなります。


とのこと。

スクリプトからのヘッダ出力では私が確認したケースでは "Cache-Control:" は出力して
いなかったのですが、サーバの方でおそらく付与されているのでしょう。
というわけで、以下のヘッダを出力することで回避することが出来ました。

header( 'Cache-Control: Private' );


とりあえず Private で指定していますが、他のものでも no-cache でなければ問題ないかと思います。


2010.07.09 追記

なんかうまいこといってるはずが、Chrome(5.0), IE(8) で「ファイルが壊れています」の表示。
いろいろごちゃごちゃやってみて、Content-Length: を取ってみたらうまく動くことを確認。
問題は確かに解消したけど、ファイルサイズ不明だからダウンロード時にプログレスバー表示が
されないのね。なんかほかとも関連した問題なんだろうけど。

テーマ : PHP
ジャンル : コンピュータ

検索フォーム
リンク
最新記事
最新コメント
カテゴリ
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。