tohokuaikiのチラシの裏

技術的ネタとか。

WordPressの編集画面がメチャ重くなったのでメタ情報のキャッシュを作って回避

調べてみると、カスタムフィールドの定義を取得するSQLで20秒も掛かってた。

カスタムフィールド使いまくってて、20万行越えてた。
過去のデータ中から、編集画面でプルダウンを作るんだけどそれはちょっと時間かかるよね…

ということで、テーマのfuncitons.phpに以下を追加。テーマディレクトリに tmpディレクトリを作ってパーミション777に。

<?php
class AnonymousTekitou
{
    /* ローカルキャッシュの時刻 */
    private $cache_lifetime  = 8000;
    
    /* ローカルキャッシュのディレクトリレベル */
    private $cache_dir_level = 2;
    

    /**
     * @brief 
     * @param 
     * @retval
     */
    public static function getInstance($cache_lifetime = null)
    {
        static $ins ;
        
        if (is_null($ins)){
            $ins = new self();
            if (!is_null($cache_lifetime)){
                $ins->cache_lifetime = $cache_lifetime;
            }
        }
        return $ins;
    }
    
    /**
     * @brief ファイルキャッシュ
     * @param 
     * @param 保存する場合は必要
     * @retval
     */
    private function cache($url, $body = null)
    {
        $cache_file = sprintf('%s/tmp/cache/%s',
                              __DIR__, $this->splitString(md5($url), $this->cache_dir_level));
        $cache_dir  = dirname($cache_file);
        if (!is_dir($cache_dir)){
            self::mkdir($cache_dir, 0777);
        }
        chmod($cache_dir, 0777);
        
        if (is_null($body)){
            if (file_exists($cache_file)){
                $s = stat($cache_file);
                if ($s['mtime'] + $this->cache_lifetime > time()){
                    $file = file($cache_file);
                    array_shift($file);
                    return implode("", $file); // キャッシュ有効・ファイルが存在してライフタイム内
                }
                else {
                    unlink($cache_file); // キャッシュ無効・再度取得
                    return null ;
                }
            }
            return false; 
        }
        else {
            file_put_contents($cache_file, $url."\n".$body);
            chmod($cache_file, 0666);
        }
    }

    

    /**
     * @brief 文字スラッシュを入れる。ex: abcdefg => a/b/c/defg
     * @param 文字列
     * @param 分割個数
     * @retval
     */
    private function splitString($str, $num) 
    {
        $ret = "";
        for ($i=0; $i< strlen($str) ;$i++){
            $ret .= $str{$i};
            if ($i<$num){
                $ret.= "/"; 
            }
        }
        return $ret;
    }
    
    
    /**
     *  mkdir -p
     *
     *  @access public
     *  @param  string  $dir    作成するディレクトリ
     *  @param  int     $mode   パーミッション
     *  @return bool    true:成功 false:失敗
     *  @static
     */
    public static function mkdir($dir, $mode)
    {
        if (file_exists($dir)) {
            return is_dir($dir);
        }

        $parent = dirname($dir);
        if ($dir === $parent) {
            return true;
        }

        if (is_dir($parent) === false) {
            if (self::mkdir($parent, $mode) === false) {
                return false;
            }
        }

        return mkdir($dir, $mode) && chmod($dir, $mode);
    }
    
    
    
    
    /**
     * @brief postmeta_form_keysのキャッシュを作成する
     * @param $WP_Post
     * @retval
     */
    public function getPostmetaFormKeysCache($post) 
    {
        global $wpdb;

        $key_name = md5(__CLASS__ . __METHOD__ . DB_NAME . __FILE__ . $_SERVER['SERVER_NAME']);

        // postがnullの時だけキャッシュを使う
        if (!is_null($post)) {
            return null;
        }

        if ($cache = $this->cache($key_name)){
            $keys = unserialize($cache);
        }
        else {
            // make cache
            $limit = apply_filters( 'postmeta_form_limit', 30 );
            $sql = "SELECT DISTINCT meta_key
          FROM $wpdb->postmeta
          WHERE meta_key NOT BETWEEN '_' AND '_z'
          HAVING meta_key NOT LIKE %s
          ORDER BY meta_key
          LIMIT %d";
            $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
            $this->cache($key_name, serialize($keys));
        }
        
        return $keys;
    }
}

add_filter('postmeta_form_keys', function($p){
    $a= AnonymousTekitou::getInstance();
    return $a->getPostmetaFormKeysCache($p);
});

Let's Encryptのための穴あけ

Let's Encryptを使うには、httpでの接続も残しておかないと更新してくれない。.well-knownにアクセスできなくて失敗する。

httpを立てておいて、httpsにリダイレクト、でその先はBasic認証アリだとか作ってるとダメ。http => https(Basic認証アリ)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: example.com
   Type:   unauthorized
   Detail: Invalid response from
   http://example.com/.well-known/acme-challenge/OjG***************************************3I:
   "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML
   2.0//EN\">\n<html><head>\n<title>401
   Unauthorized</title>\n</head><body>\n<h1>Unauthorized</"

で、こうやっておく。

httpアクセス側のhttpd.conf

<VirtualHost *:80>
        ServerAdmin webmaster@example.jp
        ServerName example.com
        DocumentRoot /web/example.com/htdocs

        <Directory /web/example.com/htdocs>
            RewriteEngine On
            RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
        </Directory>

        <Directory /web/example.com/htdocs/.well-known>
            RewriteEngine Off
            Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/example.com.error.log
        CustomLog ${APACHE_LOG_DIR}/example.com.access.log combined

</VirtualHost>

.well-knowは転送無しにして、かつ Require all granted 。これが無いとあの忌々しい

[authz_core:error] [pid 2510] [client 192.168.111.111:50355] AH01630: client denied by server configuration:

が出る。

Vue.jsのファイルをドラッグ&ドロップでIE11だけ引っかかったところ

IE11だけといいつつ、Safariは調べてないので知らない。

Vue.jsを使って

    <div class="dropArea" :class="{ dragOver: isDragOver }"
      @dragleave.prevent="onDragLeave"
      @dragover.prevent="onDragOver"
      @drop.prevent="onDrop"
      >
      <p>ここにCSVをドラッグ&ドロップしてください。</p>
    </div>

って書いたら、IE11だけ反応しなかった。普通にファイルをダウンロードしてしまう。

解決

DragEnterで引っかかっていたみたい。@dragenter.preventを入れる。

    <div class="dropArea" :class="{ dragOver: isDragOver }"
      @dragenter.prevent=""
      @dragleave.prevent="onDragLeave"
      @dragover.prevent="onDragOver"
      @drop.prevent="onDrop"
      >
      <p>ここにCSVをドラッグ&ドロップしてください。</p>
    </div>

文字列を規定の区切り文字で区切る(ったり色々する)関数

<?php
/**
 * @brief 文字列を右からN桁区切りにする
 * @param 文字列
 * @param 区切り数
 * @param 区切り文字
 * @param パディング文字
 * @param 最短文字数:足らない場合はパディングする
 * @retval
 */
function convDigit($str, $num = 3, $glue = '/', $padding = '0', $min_length = null)
{
    $str = strrev(strval($str));
    
    $ret = array();

    $fragment = "";
    for ($i=0; $i< strlen($str); $i++){
        $fragment = $str{$i}.$fragment;
        if (strlen($fragment) === $num){
            $ret[] = $fragment;
            $fragment = "";
        }
    }
    if ($fragment){
        $ret[] = sprintf('%'.$padding.$num.'s',
                         $fragment);
    }
    
    if ($min_length && $num * count($ret) < $min_length){
        $ret = array_pad($ret, ceil($min_length / $num), 
                         sprintf('%'.$padding.$num.'s', ''));
    }
    
    return implode("/", array_reverse($ret));
}

テスト

<?php
$n = "";
for ($i=1; $i<20; $i++){
     $n .= $i;
     echo convDigit($n, 3, '/', '0', 20)."\n";
}

000/000/000/000/000/000/001
000/000/000/000/000/000/012
000/000/000/000/000/000/123
000/000/000/000/000/001/234
000/000/000/000/000/012/345
000/000/000/000/000/123/456
000/000/000/000/001/234/567
000/000/000/000/012/345/678
000/000/000/000/123/456/789
000/000/000/012/345/678/910
000/000/001/234/567/891/011
000/000/123/456/789/101/112
000/012/345/678/910/111/213
001/234/567/891/011/121/314
123/456/789/101/112/131/415
012/345/678/910/111/213/141/516
001/234/567/891/011/121/314/151/617
123/456/789/101/112/131/415/161/718
012/345/678/910/111/213/141/516/171/819

日本のプロ野球の打率の推移をグラフにした

データはWikipediaより。

打率 - Wikipedia
首位打者 (日本プロ野球) - Wikipedia

f:id:tohokuaiki:20181211104744p:plain
NPBの打率グラフ

考察

  • 1975年のDHは全体には差ほど寄与してなさそう
  • 2011年の統一球はやばいだろこれっていう感じ
  • 平均打率との差が一番大きいのは、1970年の張本選手。ハリーすげぇ。

打率差ベスト20

率差 首位打者
1 1970 0.137 張本勲
2 1951 0.136 大下弘
3 1986 0.13 R.バース
4 1962 0.124 J.ブルーム
5 2000 0.123 イチロー
6 1973 0.118 王貞治
7 1989 0.118 W.クロマティ
8 1961 0.117 長嶋茂雄
9 1964 0.116 広瀬叔功
10 1957 0.115 与那嶺要
11 1994 0.114 イチロー
12 1956 0.113 与那嶺要
13 1951 0.113 川上哲治
14 2008 0.113 内川聖一
15 1966 0.113 榎本喜八
16 1980 0.109 谷沢健一
17 1969 0.108 王貞治
18 1954 0.107 与那嶺要
19 1966 0.107 長嶋茂雄
20 2015 0.107 柳田悠岐

打率差ワースト20

率差 首位打者
1 1976 0.053 吉岡悟
2 1991 0.055 平井光親
3 2005 0.055 和田一浩
4 1989 0.056 ブーマー
5 1981 0.057 落合博満
6 2009 0.06 鉄平
7 2012 0.06 角中勝也
8 2004 0.062 嶋重宣
9 1983 0.062 落合博満
10 1992 0.063 佐々木誠
11 2006 0.063 松中信彦
12 1990 0.064 J.パチョレック
13 1994 0.064 A.パウエル
14 1984 0.065 篠塚利夫
15 1975 0.065 白仁天
16 1993 0.065 辻発彦
17 2009 0.066 A.ラミレス
18 1982 0.066 落合博満
19 1975 0.067 山本浩二
20 1988 0.067 高沢秀昭

データ

セ・平均 パ・平均 セ・首率 パ・首率 セ・差分 パ・差分 セ・首位打者 パ・首位打者
1950 0.265 0.26 0.362 0.339 0.097 0.079 藤村富美男 大下弘
1951 0.264 0.247 0.377 0.383 0.113 0.136 川上哲治 大下弘
1952 0.253 0.254 0.353 0.336 0.1 0.082 西沢道夫 飯島滋弥
1953 0.255 0.247 0.347 0.318 0.092 0.071 川上哲治 岡本伊三美
1954 0.254 0.242 0.361 0.337 0.107 0.095 与那嶺要 L.レインズ
1955 0.236 0.246 0.338 0.332 0.102 0.086 川上哲治 中西太
1956 0.225 0.232 0.338 0.325 0.113 0.093 与那嶺要 豊田泰光
1957 0.228 0.235 0.343 0.331 0.115 0.096 与那嶺要 山内和弘
1958 0.231 0.236 0.32 0.314 0.089 0.078 田宮謙次郎 中西太
1959 0.23 0.241 0.334 0.323 0.104 0.082 長嶋茂雄 杉山光平
1960 0.232 0.246 0.334 0.344 0.102 0.098 長嶋茂雄 榎本喜八
1961 0.236 0.248 0.353 0.336 0.117 0.088 長嶋茂雄 張本勲
1962 0.231 0.25 0.307 0.374 0.076 0.124 森永勝治 J.ブルーム
1963 0.244 0.244 0.341 0.335 0.097 0.091 長嶋茂雄 J.ブルーム
1964 0.245 0.25 0.323 0.366 0.078 0.116 江藤愼一 広瀬叔功
1965 0.235 0.24 0.336 0.32 0.101 0.08 江藤愼一 野村克也
1966 0.237 0.238 0.344 0.351 0.107 0.113 長嶋茂雄 榎本喜八
1967 0.245 0.243 0.343 0.336 0.098 0.093 中暁生 張本勲
1968 0.24 0.244 0.326 0.336 0.086 0.092 王貞治 張本勲
1969 0.237 0.246 0.345 0.333 0.108 0.087 王貞治 永淵洋三・張本勲
1970 0.234 0.246 0.325 0.383 0.091 0.137 王貞治 張本勲
1971 0.23 0.253 0.32 0.337 0.09 0.084 長嶋茂雄 江藤愼一
1972 0.245 0.256 0.329 0.358 0.084 0.102 若松勉 張本勲
1973 0.237 0.254 0.355 0.337 0.118 0.083 王貞治 加藤秀司
1974 0.249 0.247 0.332 0.34 0.083 0.093 王貞治 張本勲
1975 0.252 0.254 0.319 0.319 0.067 0.065 山本浩二 白仁天
1976 0.265 0.256 0.355 0.309 0.09 0.053 谷沢健一 吉岡悟
1977 0.271 0.255 0.358 0.329 0.087 0.074 若松勉 有藤道世
1978 0.269 0.265 0.348 0.354 0.079 0.089 水谷実雄 佐々木恭介
1979 0.262 0.274 0.346 0.364 0.084 0.09 F.ミヤーン 加藤英司
1980 0.26 0.273 0.369 0.358 0.109 0.085 谷沢健一 L.リー
1981 0.265 0.269 0.358 0.326 0.093 0.057 藤田平 落合博満
1982 0.255 0.259 0.351 0.325 0.096 0.066 長崎啓二 落合博満
1983 0.27 0.27 0.353 0.332 0.083 0.062 真弓明信 落合博満
1984 0.269 0.265 0.334 0.355 0.065 0.09 篠塚利夫 ブーマー
1985 0.272 0.272 0.35 0.367 0.078 0.095 R.バース 落合博満
1986 0.259 0.27 0.389 0.36 0.13 0.09 R.バース 落合博満
1987 0.263 0.263 0.333 0.366 0.07 0.103 篠塚利夫正田耕三 新井宏昌
1988 0.256 0.26 0.34 0.327 0.084 0.067 正田耕三 高沢秀昭
1989 0.26 0.266 0.378 0.322 0.118 0.056 W.クロマティ ブーマー
1990 0.262 0.264 0.326 0.338 0.064 0.074 J.パチョレック 西村徳文
1991 0.256 0.259 0.34 0.314 0.084 0.055 古田敦也 平井光親
1992 0.256 0.259 0.331 0.322 0.075 0.063 J.ハウエル 佐々木誠
1993 0.252 0.254 0.329 0.319 0.077 0.065 T.オマリー 辻発彦
1994 0.26 0.271 0.324 0.385 0.064 0.114 A.パウエル イチロー
1995 0.255 0.248 0.355 0.342 0.1 0.094 A.パウエル イチロー
1996 0.265 0.258 0.34 0.356 0.075 0.098 A.パウエル イチロー
1997 0.258 0.266 0.335 0.345 0.077 0.079 鈴木尚典 イチロー
1998 0.259 0.265 0.337 0.358 0.078 0.093 鈴木尚典 イチロー
1999 0.268 0.259 0.369 0.343 0.101 0.084 R.ローズ イチロー
2000 0.262 0.264 0.346 0.387 0.084 0.123 金城龍彦 イチロー
2001 0.263 0.264 0.333 0.346 0.07 0.082 松井秀喜 福浦和也
2002 0.257 0.255 0.343 0.34 0.086 0.085 福留孝介 小笠原道大
2003 0.269 0.276 0.34 0.36 0.071 0.084 今岡誠 小笠原道大
2004 0.275 0.277 0.337 0.358 0.062 0.081 嶋重宣 松中信彦
2005 0.27 0.267 0.344 0.322 0.074 0.055 青木宣親 和田一浩
2006 0.263 0.261 0.351 0.324 0.088 0.063 福留孝介 松中信彦
2007 0.265 0.262 0.346 0.334 0.081 0.072 青木宣親 稲葉篤紀
2008 0.265 0.265 0.378 0.332 0.113 0.067 内川聖一 リック
2009 0.256 0.267 0.322 0.327 0.066 0.06 A.ラミレス 鉄平
2010 0.267 0.27 0.358 0.346 0.091 0.076 青木宣親 西岡剛
2011 0.242 0.251 0.316 0.338 0.074 0.087 長野久義 内川聖一
2012 0.244 0.252 0.34 0.312 0.096 0.06 阿部慎之助 角中勝也
2013 0.254 0.262 0.333 0.341 0.079 0.079 T.ブランコ 長谷川勇也
2014 0.264 0.257 0.338 0.331 0.074 0.074 M.マートン 糸井嘉男
2015 0.249 0.256 0.336 0.363 0.087 0.107 川端慎吾 柳田悠岐
2016 0.253 0.259 0.344 0.339 0.091 0.08 坂本勇人 角中勝也
2017 0.251 0.25 0.323 0.322 0.072 0.072 宮崎敏郎 秋山翔吾
2018 0.259 0.254 0.348 0.352 0.089 0.098 D.ビシエド 柳田悠岐