接触確認アプリで「接触したとPUSH通知」→「アプリを開くと接触なし」になる問題

起きている現象

以下のような現象が起きてるようです

  • 接触確認アプリ(COCOA)から 「 COVID-19 にさらされた可能性があります」 というプッシュ通知が届く
  • 通知からアプリを開くと「 陽性者との接触は確認されませんでした 」という表示になっている
  • ( iOSでは通知は一度見ると消えるので、その後は通知は再度確認できなくなる )

Twitter上で、この現象が起きた方が複数確認できます


必要な対応

現在の厚生労働省の公式見解

厚生労働省の「接触確認アプリ利用者向けQ&A」によると、この現象が起きた場合メールで問い合わせる必要があるとのことです。

接触確認アプリ利用者向けQ&A|厚生労働省

https://i.gyazo.com/d80ba0246b733efe394b2f87aa906f63.png

以前は異なる見解だったことに注意

8月3日時点では現在と全く異なる見解で、通知がきてもアプリ上が接触者なしだと安心してくださいという見解だったようです。

上記の古い見解を見てメールを送ってない方がいれば、現在の見解にしたがってメールでの問い合わせをしたほうが良いと思われます。


接触を「一致したキー」から確認する方法

問い合わせた方によると「接触チェックの記録内で 一致したキーの数が1つ以上の場合は、陽性者との接触があったと判断してください」という回答をもらった方がいます。

「一致したキー」の確認方法 (iOSの場合)

1 設定を開きます

https://i.gyazo.com/28a15f8731cf16e7825074707fb28ef7.png

2 設定画面の下のアプリ一覧から「接触確認アプリ」を選びます

https://i.gyazo.com/b72570f57baa69c939266c458f26a87d.png

3 「COVID-19接触ログ記録の設定」を押します

https://i.gyazo.com/f61bb2a701e07c57e05a99de8eb25295.png

4 「接触チェックの記録」を押します

https://i.gyazo.com/73230bb106a3e1e684f5ff2001237b0f.png

5 表示されている時刻を上から確認していきます。一番上のものから押します

https://i.gyazo.com/f9110f369e8b8a9e78a5c88790aa5a2c.png

  1. 全ての記録の「一致したキー」が0になっているかを確認します。

https://i.gyazo.com/3da3d7572bf372f0341afd8498ae143e.png

通知が来たような気がするが確認できない方で、1のものが存在すれば、その情報と合わせてメールで問い合わせを行ってみた方が良いと思われます。

記録が多すぎて確認が大変な場合

1「接触チェックの記録」画面の「接触チェックの記録を書き出す」を押します

https://i.gyazo.com/1d794205e9ea4215754b7637365f4342.png

2 コピーを選びます

https://i.gyazo.com/a303c0b24de58032f062efef8faa7b59.png

3 コピーした内容をLINEでもメールでもメモアプリでも良いので、どこかに貼り付けてください

https://i.gyazo.com/6f401f90c4117c12477860fcaec40263.png

貼り付けた内容に「MatchCount」という文字が入ってる行の数字が全て0かを確認します。 通知が来たような気がするが確認できない方で、1のものが存在すれば、その情報と合わせてメールで問い合わせを行ってみた方が良いと思われます。

moshを導入しようとして凡ミスでハマった

moshを導入しようとして凡ミスしてたのでメモしておきます.

クライアント側に出ていたエラー

http://tukaikta.blog135.fc2.com/blog-entry-210.html

上記のエントリを参考にさせていただきながらサーバ側( sakuraのVPS )とクライアント側( mac )の設定を行いました。 無事設定完了して、クライアント側のmacからmoshを起動しようとすると下記のようなエラーがでて起動できませんでした。

mosh: Nothing received from server on UDP port 60001.

Firewallの確認

サーバ側のFirewallはiptablesに以下のように設定していたのでポートは開いているような気がしていました。

-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 60000:61000 -j ACCEPT

そこで、実際に通信が行われているか確認するためにサーバ側でtcpdumpを実行して確認してみました。

tcpdump host (クライアント側のhostname) and not (SSHのポート) # sshのpacketが邪魔なのでフィルタリングしておく
22:53:19.477223 IP (クライアント側のhostname).60950 > (サーバ側のhostname).60001: UDP, length 71
22:53:19.477271 IP (サーバ側のhostname) > (クライアント側のhostname): ICMP host (サーバ側のhostname) unreachable - admin prohibited, length 107

あぁ。。。と思いiptablesの設定を見直してみると icmp-host-profibitedの設定がmoshのポート設定の上にきてしまっていました。。
iptablesは上からフィルタが適応されているので、これでは当然動かないですね。凡ミス。

-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
....
# 先にicmp-host-prohibitedの設定が適応されてしまているので動かない
-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 60000:61000 -j ACCEPT

以下のように順番を逆にすると無事動いた。

-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 60000:61000 -j ACCEPT
...
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited

凡ミスでタイムロスしないように気をつけます。
それにしてもmosh、快適ですね・・・!
回線がe-mobileしかない貧民なので、感動しました。

cakePHP内でPEAR Services_Amazonのキャッシュ機能を使おうとするとエラー

気がついたら1年ぶり以上のCake関係の記事。
さて、最近またCakePHPを使ってWEBアプリを組んでいるので久々に更新します。


最近、Product Advertising APIと名前が変わったAmazonのAPI
これを使うのに便利なライブラリとしてPEAR Services_Amazonがあります。
このライブラリを使用すると、通信結果結果を配列で取得、Amazonから取得したデータのキャッシュの実装などなどが簡単に行えます。


が、CakePHP内部で、このライブラリのキャッシュ関係の部分が動かずハマってしまったので、かつ同じようにハマる人がいそうなのでメモしておきます。

発生したエラーについて

CakePHPの、あるmodelの中で、次のようなコードを書きました

<?php
  require_once("Services/Amazon.php");
  $amazon = new Services_Amazon($amazon_access_key, $amazon_secret_key, $amazon_associate_key);
  $amazon->setLocale("jp");
  $amazon->setCache('file', array('cache_dir' => '/path/to/cache/dir/'));
?>

すると以下のようなエラーが発生
Fatal error: Call to undefined method Cache::get() in /usr/share/php/Services/Amazon.php on line 1361

エラーが起こっているServices/Amazon.phpの処理を見て、原因特定

1361行目のクラスの_sendRequestメソッド内の_cacheというプロパティからgetメソッドを実行しようとしているところでエラーが起こっています。

<?php
$cache = $this->_cache->get($cache_id);
?>
・$this->_cacheの初期化

ということで、この_cacheプロパティに、どのようなインスタンスが設定されるのかをチェック。
397行目から、始まるsetCacheメソッド内で初期化されています。

<?php
 397     function setCache($container = 'file', $container_options = array())
 398     {
 399         if(!class_exists('Cache')){
 400             @include_once 'Cache.php';
 401         }
 402 
 403         @$cache = new Cache($container, $container_options);
 404 
 405         if (is_object($cache)) {
 406             $this->_cache = $cache;                                                                                     
 407         } else {
 408             $this->_cache = null;
 409             return PEAR::raiseError('Cache init failed');
 410         }
 411 
 412         return true;
 413     }

エラー処理も、きちんとしてるし問題なさそうです。
今回、発生したエラーはCache::getというメソッドが存在していねぇよっというエラーなので、$cacheのメソッド一覧を確認してみましょう。
406行目の下に次の行を追加してみます

<?php
 407 print_r( get_class_methods($this->_cache) );
>?

以下が結果です。

<?php
Array
(
    [0] => getInstance
    [1] => __loadEngine
    [2] => config
    [3] => engine
    [4] => set
    [5] => gc
    [6] => write
    [7] => read
   -----
    [20] => cakeError
    [21] => _persist
    [22] => _savePersistent
    [23] => __openPersistent
)
>?

あ、あれ、このメソッドどこかで見たことあるぞ。。。っていうか配列の20個目,cakeとかいう文字が。。。PEARのライブラリなのに。。。
つまり、CakePHP内でもCacheという名前のクラスがあって、それがPEARのCacheクラスと競合していました。
Services/Amazon.phpPEAR Cacheを使用したいのに、CakePHPのCacheクラスのインスタンスが生成されてしまっています。

解決方法(暫定

ということで解決方法です。
今回とった方法は、あんまりよくないかもしれないけど、PEARのライブラリを書き換えてしまいます。
1.Cache.phpをコピーしてCache_PEAR.phpを作成
まず、クラス名が被っているのがまずいのでPEAR::Cacheのクラス名を変更します。
直でCache.phpを書き換えてもいいのだけど、一応コピーをとって、そっちを書き換える方針で。
2.Cache_PEAR.phpの次の2箇所(クラス名とコンストラクタ部分)を変更

  • 66行目
    • 変更前:class Cache extends PEAR
    • 変更後:class Cache_PEAR extends PEAR
  • 129行目
    • 変更前:function Cache_PEAR($container, $container_options = '')
    • 変更後:function Cache_PEAR($container, $container_options = '')

3.Services/Amazon.phpでCacheインスタンスの代入部分を変更

  • 変更前
<?php
 399         if(!class_exists('Cache')){
 400             @include_once 'Cache.php';
 401         }
 403         @$cache = new Cache($container, $container_options);
>?
  • 変更後
<?php
 399         if(!class_exists('Cache_PEAR')){
 400             @include_once 'Cache_PEAR.php';
 401         }
 403         @$cache = new Cache_PEAR($container, $container_options);
>?

結果

無事、Services_Amazonのキャッシュ部分が動きました。

cakePHPのfindAllで柔軟なJOINを行う

やりたいこと

あるコントローラでfindを実行する際に,一箇所でのみ特定のテーブルとJOINをしたり,状況によってJOIN設定を変更する方法について考える.


もっとも、そこまで特殊で数箇所でしか使用しないリレーションの場合,直接SQLを書いてしまったほうがラクだったりもする。
今回、findをJOINするのは,他のコンポーネントとの兼ね合い。特にPaginationコンポーネントを利用する場合に、直接SQLを書くとコンポーネントを利用したページング設定に手間がかかりそうだから。


$model->beforeFindを設定することで、そのmodelに関するfindのSQLを発行するときのJOINの設定などを行うことができるが、これはmodel自体の設定のため、findを使用している箇所全てに適用される。
(詳細は→CakePHP findAll で INNER JOIN する方法 | Sun Limited Mt. )
ということで今回、もう少し柔軟にJOINを発行する方法について考えてみる。

環境

php5 + cakephp 1.1.17.5612

とりあえずfindAllのコードを見てみる

cakephpの./cake/libs/model/model_php5.phpないのfindAllの部分を読んでみると..

  • $queryDataにSQLに関する情報が入っている。
  • $queryDataの'joins'にJOINの情報を入れてやればやればよさそう!
    • cakePHP自体のコード変更に抵抗がない場合はfindAllに引数$joinを追加してやるのが一番てっとり早そう
    • cakePHP自体のコード変更ができない場合は$model->beforeFindを使うしかない
    • 2つの場合、それぞれについてfind毎にJOINする方法を考える

cakePHP自体のコード変更する場合

  • ./cake/libs/model/model_php5.phpを以下のように変更
<?php
   //最終引数に$joinsを追加
   function findAll($conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null,$joins = null) {

		//--------略-----------------

        $queryData = array('conditions' => $conditions,
                            'fields'    => $fields,
                            'joins'     => $joins, //変更部分
                            'limit'     => $limit,
                            'offset'    => $offset,
                            'order'     => $order
        );


		//--------略-----------------

        return $return;
    }
?>
  • コントローラー内での使い方は以下のようになる
<?php
    $joins[] = array(
        "type" => "INNER",
        "alias" => "",
        "table" => INNER JOIN するテーブル,
        "conditions" => INNER JOIN の ONに指定する条件,
    );

    $findAll($conditions , $fields, $order, $limit, $page, $recursive,$joins);
?>

beforeFindを用いる場合(cakePHP本体のコード変更しない場合)

  • cakePHP本体のコードが変更できない場合は$model->beforeFindを定義することになる
  • しかしbeforeFindはモデル自体に適応されるため、コントローラーすべてのfindに適用される
  • find毎に設定を変更するためにプロパティを追加する方法を考えてみる
./app/model/モデル名.phpを編集
  • プロパティにjoinSettings、メソッドにbeforeFindを以下のように追加
<?php
    var $joinSettings = array();

    function beforeFind(&$queryData){
            $queryData["joins"] = $this->joinSettings;
            return true;
        }
コントローラー側での使い方
  • JOINが必要ないときは通常にfindを使用
  • JOINが必要なときはfindの前に以下のように記述
<?php
        $this->モデル名->joinSettings[] = array(
                'type' => 'LEFT',
                'alias' => '',
                'table' => 'テーブル名',
                'conditions' => 条件,
            );

?>
  • これで特定の箇所だけ特定のJOINを実行できるはず

英語

なんとなくこれから英語を趣味的に勉強してこーかなーと思ってます。
なにかをチマチマ、コツコツとなんかをやるのがわりと好きなんです。


ということでブログ左に「はてなグラフの」僕の英語学習時間のグラフを今日から表示しました。
累計270時間になってるのは、実は去年に春〜秋ぐらいまでは勉強してたからです。


よかった参考書なんかがあればここで紹介しますね。