カテゴリー
jQuery PHP

Access-Control-Allow-Origin ヘッダーに見つかりません。

異なるドメインから利用される Webサービスは、アクセスを許可するドメインをAccess-Control-Allow-Origin ヘッダーで制限できます。

どのドメインからでもアクセスを許可するには

Access-Control-Allow-Origin: *

ドメインを https://www.northwind.mydns.jp に限定するには

Access-Control-Allow-Origin: https://www.northwind.mydns.jp

Access-Control-Allow-Origin の指定がない場合は同一ドメインのみアクセス可となります。つまり、他のドメインからアクセスした場合、「Access-Control-Allow-Origin ヘッダーに見つかりません。」となります。

PHPでヘッダを書き出すには

header("Access-Control-Allow-Origin: *");

と1行追加で対応できます。

カテゴリー
PHP

PHP socket_connect のタイムアウト

PHP でサーバーからクライアントへデータを通知するのにソケット通信を行う場合、クライアント側のアプリが接続可能状態でないとソケットの接続が長い時間戻って来なくなります。それを回避するには、socket_set_option でタイムアウト時間を設定します。

<?php
$address = "192.168.1.xxx";    // 送信先のIPアドレス
$port = xxxx;                  // 送信先のポート
$msg = "送信するメッセージです。";
$res = "";

$start = time();

// TCP/IP ソケット作成
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

if ($socket === false)
{
    $res = "socket_create() 失敗: ".socket_strerror(socket_last_error()).PHP_EOL;
}
else
{
    // 送信タイムアウト時間の設定(10秒)
    $timeout = array('sec' => 10, 'usec' => 0);
    socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout);

    // ソケット接続
    $result = socket_connect($socket, $address, $port);

    if ($result === false)
    {
        $res = "socket_connect() 失敗: ".socket_strerror(socket_last_error($socket)).PHP_EOL;
    }
    else
    {
        $result = socket_write($socket, $msg, strlen($msg));
        if ($result === false)
        {
            $res = "socket_write() 失敗: ".socket_strerror(socket_last_error($socket)).PHP_EOL;
        }
        else
        {
            $res = "送信しました。".PHP_EOL;
        }
    }
    // ソケットを閉じる
    socket_close($socket);
}

$end = time();

echo $res;
echo ($end - $start)." 秒".PHP_EOL;
?>
カテゴリー
jqGrid PHP

jqGridの検索と検索演算子

jqGrid の検索機能では検索条件を $_GET パラメータとして渡されます。

検索パラメータは以下の3つです。

searchField: 検索フィールド
searchOper: 検索条件(演算子)
searchString: 検索する値

例えば searchField が “ID”、searchOper が “eq”、searchString が “100” ならば SQL 文に置き換えると ID = 100 という Where 句になります。

ということは、searchOper に入ってくる値にはどんなものがあるかを知っている必要があります。

そこで調べました。以下の簡単な jqGrid とナビゲーションバーに検索ボタンを表示させ、検索ボタンをクリックすると、デフォルトでは以下の検索ダイアログが表示されます。

jqgrid-search

どの演算子を表示させるかは、jqGrid の各カラムの定義で指定ができるのですが、今回は割愛し、各jqGrid の検索演算子とSQLの演算子の対比表にまとめました。

表示名 searchOperの値 SQL 演算子
次に等しい eq =
次に等くない ne <>
次より小さい lt <
次より等しいか小さい le <=
次より大きい gt >
次より等しいか大きい ge >=
次で始まる bw LIKE ‘%searchStr’
次で始まらない bn NOT LIKE ‘%searchStr’
次で終わる ew LIKE ‘searchStr%’
次で終わらない en NOT LIKE ‘searchStr%’
次を含む in LIKE ‘%searchStr%’
次を含まない ni NOT LIKE ‘%searchStr%’
次に含まれる cn LIKE ‘%searchStr%’
次に含まれない nc NOT LIKE ‘%searchStr%’
is null nu IS NULL
is not null nn IS NOT NULL

※ ‘searchStr’ は $_GET[‘searchString’] で渡される値です。
※ 「次に含まれる」、「次を含む」と「次に含まれない」、「次を含まない」は同じですね。
参考:https://stackoverflow.com/questions/9383267/what-is-the-usage-of-jqgrid-search-is-in-and-is-not-in

<table id="list"></table>
<div id="statusbar"></div>

<script type="text/javascript">
    $(document).ready(function () {
        $("#list").jqGrid({
            datatype: "json",
            url: "getdata.php",
            height: 250,
            width: 780,
            colModel: [
                { label: 'No', name: 'id', width: 75, key:true },
                { label: '日付', name: 'invdate', width: 90 },
                { label: 'クライアント', name: 'name', width: 100 },
                { label: '金額', name: 'amount', width: 80 },
                { label: '税', name: 'tax', width: 80 },
                { label: '合計', name: 'total', width: 80 },
                { label: '備考', name: 'note', width: 150 }
            ],
            viewrecords: true, // ページ、件数をツールバー上に表示
            pager: "#statusbar",
            caption: "jqGrid JSON 簡単サンプル"
        });

        // ナビゲーションの検索を有効にする
        jQuery("#list").jqGrid('navGrid','#statusbar',{del:false, add:false, edit:false, search:true});
    });
</script>

jqGrid を URL で指定したデータソースかデータを取得する方法では、データソース側では、これらの検索演算子に応じた検索結果を返さないとなりません。;-)

カテゴリー
Asterisk IP-PBX PHP

Asterisk AGI PHPスクリプトの改行コード

オープンソースのIP-PBXである Asterisk は 機能を追加するために AGI (Asterisk Gateway Interface) というインターフェースがあります。さまざまな言語 (Perl, PHP etc.) でデータベースへアクセスするなど電話とコンピュータシステムの連携することができます。

現在開発中のシステムで AGI スクリプトを PHP で書いていて気づいた点があったので備忘録に。

例えば、以下のdefault コンテキストのエクステンションから起動される hangup.php という AGI スクリプトがあります。処理は電話の切断情報をデータベースに書き込んで終了します。

[default]
.. 省略 ..
exten => h,1,NoOp(${HANGUPCAUSE})
 same => n,NoOp(${CHANNEL})
 same => n,NoOp(${AVAILSTATUS})
 same => n,AGI(hangup.php)

コマンドラインから hangup.php 単体を実行すると期待どおりの動作で問題なかったのですが、エクステンションから起動されると、正常終了するものの処理が行われません。

正常に動作するスクリプトと見比べること数時間。。

違いといえば、正常動作するスクリプトは改行コードが LF のみで、hangup.php は改行コードが CRLF になっていることくらい。

ものは試しに改行コードを LF に変換して実行すると、期待通りの動作となりました。 🙂

ということで、AGIスクリプトの改行コードは LF のみでないと期待通りの動作にならないことがある。

ちなみに、Asterisk のバージョンは 1.8.25 です。

カテゴリー
PHP

URLからXMLファイルの読み込み

XMLデータを指定したURLから読み込むには、

$xml = simplexml_load_file($url);

または、

$xml = simplexml_load_string(file_get_contents($url));

で行えます。しかし、サーバーの設定によって指定した URL がリダイレクトされている場合には、リダイレクト先のURLから読み込みを行ってくれないようです。

例えば、curl_getinfo 関数で、当サイトのブログの RSS フィードを取得してみます。

結果は:

    [url] => https://www.northwind.mydns.jp/samples/blog/feed/
    [content_type] => text/html
    [http_code] => 301
    [header_size] => 348
    [request_size] => 71
    [filetime] => -1
    [ssl_verify_result] => 0
    [redirect_count] => 0
    [total_time] => 1.21189
    [namelookup_time] => 0.003149
    [connect_time] => 0.003198
    [pretransfer_time] => 0.0032
    [size_upload] => 0
    [size_download] => 0
    [speed_download] => 0
    [speed_upload] => 0
    [download_content_length] => 0
    [upload_content_length] => 0
    [starttransfer_time] => 1.211865
    [redirect_time] => 0
    [certinfo] => Array
        (
        )

    [redirect_url] => https://www.northwind.mydns.jp/samples/blog/feed/

http_code が 301 で、redirect_url にリダイレクト先の URL が返されました。

つまり、

$xml = simplexml_load_file("https://www.northwind.mydns.jp/samples/blog/feed/");

では期待していたフィードが得られないというわけです。

リダイレクト先の URL を指定すれば良いのですが、指定した URL がリダイレクトされているか不明の場合もあるので、getXmlFromUrl 関数を作ってみました。

function getXmlFromUrl($url, $defTimeout = 5) {
    $resultSet = false;
    $timeout = $defTimeout; // 0 をセットするとタイムアウトしない

    try {
        $ch = curl_init();

        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

        $res = curl_exec($ch);
        $info = curl_getinfo($ch);

        curl_close($ch);    

        if ($res && $info['http_code'] == 200) {
            $resultSet = simplexml_load_string($res);
        } else if ($info['http_code'] == 301) { // リダイレクト!
            $resultSet = getXmlFromUrl($info['redirect_url'], $defTimeout);
        } else {
            $resultSet = false;
        }
    } catch (Exception $e) {
    }

    return $resultSet;
}