<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 15103 -->
<sect1 id="zend.timesync.working">

    <title>Zend_TimeSync の動作</title>

    <para>
        <classname>Zend_TimeSync</classname> は、指定した任意の
        <emphasis role="strong">NTP</emphasis> タイムサーバあるいは
        <emphasis role="strong">SNTP</emphasis> タイムサーバから実際の時刻を返します。
        自動的に複数のサーバを処理することができ、シンプルなインターフェイスを提供します。
    </para>

    <note>
        <para>
            この章のすべてのサンプルでは、一般に公開されているタイムサーバのひとつを使用します。
            私たちは <emphasis role="strong">0.europe.pool.ntp.org</emphasis>
            を使用しますが、あなたの環境にあわせて最も近いタイムサーバを使うことをお勧めします。
            詳細は <ulink url="http://www.pool.ntp.org">http://www.pool.ntp.org</ulink>
            を参照ください。
        </para>
    </note>

    <sect2 id="zend.timesync.working.generic">

        <title>一般的なタイムサーバへのリクエスト</title>

        <para>
            タイムサーバから時刻を取得するのはきわめて簡単です。
            単に時刻を取得したいタイムサーバを指定するだけでいいのです。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync('0.pool.ntp.org');

print $server->getDate()->getIso();
]]>
        </programlisting>

        <para>
            このとき <classname>Zend_TimeSync</classname> の裏側では何が起こっているのでしょうか?
            まず、指定したサーバの構文をチェックします。つまり今回の例では、
            '<code>0.pool.ntp.org</code>' がタイムサーバのアドレスとして正しい形式かどうかを確認します。
            それから、<code>getDate()</code> をコールする際に実際にタイムサーバを設定し、
            そのサーバの時刻を返します。<classname>Zend_TimeSync</classname>
            は、スクリプトが動作しているサーバの時刻と返された時刻とを比較し、
            修正済みの時刻を表す <classname>Zend_Date</classname> オブジェクトを返します。
        </para>

        <para>
            <classname>Zend_Date</classname> やそのメソッドについての詳細は
            <link linkend="zend.date.introduction"><classname>Zend_Date</classname></link>
            を参照ください。
        </para>

    </sect2>

    <sect2 id="zend.timesync.working.multiple">

        <title>複数のタイムサーバ</title>

        <para>
            すべてのタイムサーバが常に使用可能で時刻を返してくれるとは限りません。
            たとえばメンテナンス中などの理由でサーバに到達できないこともありえます。
            タイムサーバから時刻を取得できなかった場合は、例外が発生します。
        </para>

        <para>
            この問題への対策として、<classname>Zend_TimeSync</classname>
            では複数のタイムサーバを処理できるようになっており、
            ひとつのタイムサーバが使用できなくても代替サーバを使用できるようになっています。
            これを利用するには二通りの方法があります。
            インスタンスを作成する際にタイムサーバの配列を指定するか、
            後から <code>addServer()</code> メソッドでタイムサーバを追加するかのいずれかです。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('0.pool.ntp.org',
                                  '1.pool.ntp.org',
                                  '2.pool.ntp.org'));
$server->addServer('3.pool.ntp.org');

print $server->getDate()->getIso();
]]>
        </programlisting>

        <para>
            追加できるタイムサーバの数には制限はありません。
            あるタイムサーバへの接続に失敗すると、
            <classname>Zend_TimeSync</classname> はその次に指定されたタイムサーバへの接続を試みます。
        </para>

        <para>
            タイムサーバは複数指定することをお勧めします。
            その場合は、タイムサーバに名前をつけなければなりません。
            名前は配列のキーで指定することもできますが、
            初期化やタイムサーバの追加の際に 2 番目のパラメータで指定することもできます。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('generic'  => '0.pool.ntp.org',
                                  'fallback' => '1.pool.ntp.org',
                                  'reserve'  => '2.pool.ntp.org'));
$server->addServer('3.pool.ntp.org', 'additional');

print $server->getDate()->getIso();
]]>
        </programlisting>

        <para>
            タイムサーバの名前を設定することで、
            特定のタイムサーバにリクエストを送ることができるようになります。
            その方法については本章の後半で説明します。
        </para>

    </sect2>

    <sect2 id="zend.timesync.working.protocol">

        <title>タイムサーバのプロトコル</title>

        <para>
            タイムサーバにはさまざまな形式があります。
            公開されているタイムサーバのほとんどは、
            <emphasis role="strong">NTP</emphasis> プロトコルを使用するものです。
            しかし、それ以外のプロトコルを使用しているサーバもあります。
        </para>

        <para>
            タイムサーバのアドレスに、適切なプロトコルを指定することができます。
            <classname>Zend_TimeSync</classname> がサポートしているプロトコルは 2 種類で、
            デフォルトのプロトコルは <emphasis role="strong">NTP</emphasis> です。
            NTP しか使用しないのなら、先ほどまでの例のようにプロトコル指定を省略しても構いません。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('generic'  => 'ntp:\\0.pool.ntp.org',
                                  'fallback' => 'ntp:\\1.pool.ntp.org',
                                  'reserve'  => 'ntp:\\2.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com', 'additional');

print $server->getDate()->getIso();
]]>
        </programlisting>

        <para>
            <classname>Zend_TimeSync</classname> は複数のタイムサーバを使用することができます。
            特定のプロトコルだけでなく、個々のサーバに対して別のプロトコルも指定できるようになっています。
        </para>

    </sect2>

    <sect2 id="zend.timesync.working.ports">

        <title>タイムサーバのポートの指定</title>

        <para>
            ウェブにおけるさまざまな他のプロトコルと同様、<emphasis role="strong">NTP</emphasis> や
            <emphasis role="strong">SNTP</emphasis> にも標準のポート番号があります。
            NTP が使用するポートは <emphasis role="strong">123</emphasis> で、
            SNTP は <emphasis role="strong">37</emphasis> を使用します。
        </para>

        <para>
            しかし、実際には使われているポートが違うこともあります。
            使用するポートは、サーバごとにアドレス内に指定することができます。
            ポートを指定するには、アドレスに続けてその数字を指定します。
            ポートを指定しなかった場合は、<classname>Zend_TimeSync</classname> は標準のポートを使用します。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('generic'  => 'ntp:\\0.pool.ntp.org:200',
                                  'fallback' => 'ntp:\\1.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com:399', 'additional');

print $server->getDate()->getIso();
]]>
        </programlisting>

    </sect2>

    <sect2 id="zend.timesync.working.options">

        <title>タイムサーバ用のオプション</title>

        <para>
            実際のところ <classname>Zend_TimeSync</classname> で使用するオプションはひとつだけで、
            それも内部的に使用するものです。しかし、必要に応じて任意のオプションを指定して
            リクエストを送信することができます。
        </para>

        <para>
            <emphasis role="strong">timeout</emphasis> オプションは、
            応答がない状態が何秒続けば接続に失敗したとみなすのかを表します。
            デフォルトの値は <emphasis role="strong">1</emphasis> で、
            タイムサーバからの応答が 1 秒以内に返ってこなかった場合に
            <classname>Zend_TimeSync</classname> は別のタイムサーバに処理を移します。
        </para>

        <para>
            <code>setOptions()</code> メソッドを使用すれば、任意のオプションを指定することができます。
            このメソッドには、オプション名とその値を関連付けた配列を指定します。
            既に設定済みのオプションは、新しい値で上書きされます。
            どんなオプションが設定されているのかを知りたい場合は
            <code>getOptions()</code> メソッドを使用します。
            このメソッドにキーを指定した場合はそのオプションの値を返します。
            指定しなかった場合は、すべてのオプションを返します。
        </para>

        <programlisting role="php"><![CDATA[
Zend_TimeSync::setOptions(array('timeout' => 3, 'myoption' => 'timesync'));
$server = new Zend_TimeSync(array('generic'  => 'ntp:\\0.pool.ntp.org',
                                  'fallback' => 'ntp:\\1.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com', 'additional');

print $server->getDate()->getIso();
print_r(Zend_TimeSync::getOptions();
print "Timeout = " . Zend_TimeSync::getOptions('timeout');
]]>
        </programlisting>

        <para>
            ご覧のとおり、<classname>Zend_TimeSync</classname> のオプションは静的なものです。
            つまり、すべての <classname>Zend_TimeSync</classname> のインスタンスで同じ設定が共用されます。
        </para>

    </sect2>

    <sect2 id="zend.timesync.working.different">

        <title>別のタイムサーバの使用法</title>

        <para>
            時間を取得したい場合、デフォルトでは最初に指定したサーバにリクエストを送信します。
            しかし、別のタイムサーバを指定してリクエストしたほうが便利なこともあります。
            その場合は <code>setServer()</code> メソッドを使用します。
            使用するタイムサーバを指定するには、
            タイムサーバのエイリアスをこのメソッドのパラメータとして指定します。
            実際に使われるタイムサーバを知りたい場合は、単に
            <code>getServer()</code> メソッドをコールします。
            タイムサーバのエイリアスを指定すると、そのタイムサーバを返します。
            パラメータを省略した場合は、現在のタイムサーバを返します。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('generic'  => 'ntp:\\0.pool.ntp.org',
                                  'fallback' => 'ntp:\\1.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com', 'additional');

$actual = $server->getServer();
$server = $server->setServer('additional');
]]>
        </programlisting>

    </sect2>

    <sect2 id="zend.timesync.working.informations">

        <title>タイムサーバからの情報</title>

        <para>
            タイムサーバは、時刻以外にも付加情報を提供します。
            この情報を取得するには <code>getInfo()</code> メソッドを使用します。
        </para>

        <programlisting role="php"><![CDATA[
$server = new Zend_TimeSync(array('generic'  => 'ntp:\\0.pool.ntp.org',
                                  'fallback' => 'ntp:\\1.pool.ntp.org'));

print_r ($server->getInfo());
]]>
        </programlisting>

        <para>
            どのような情報が得られるのかは、
            使用しているプロトコルやサーバによってさまざまに異なります。
        </para>

    </sect2>

    <sect2 id="zend.timesync.working.exceptions">

        <title>例外処理</title>

        <para>
            すべてのタイムサーバで発生した例外は、ひとつの配列にまとめて返されます。
            発生した例外をすべて処理するには、次の例のようにします。
        </para>

        <programlisting role="php"><![CDATA[
$serverlist = array(
        // 無効なサーバを指定します
        'invalid_a'  => 'ntp://a.foo.bar.org',
        'invalid_b'  => 'sntp://b.foo.bar.org',
);

$server = new Zend_TimeSync($serverlist);

try {
    $result = $server->getDate();
    echo $result->getIso();
} catch (Zend_TimeSync_Exception $e) {

    $exceptions = $e->get();

    foreach ($exceptions as $key => $myException) {
        echo $myException->getMessage();
        echo '<br />';
    }
}
]]>
        </programlisting>
    </sect2>
</sect1>
