ホーム > タグ > programming

programming

mod_proxyとmod_ext_filterで画像圧縮プロキシを作る試み

ということで,apacheのmod_proxyを使ったフォワードプロキシを構成しているんですが,ただ単にプロキシとして使っても面白くないので,貧弱回線用に通信負荷を減らす圧縮プロキシにしちゃいました.要件は以下の通り.

  1. mod_deflateによるgzip圧縮転送
  2. mod_ext_filterを駆使した画像圧縮

ということで,mod_proxyを以下のように設定しました.動いているのであっていると思います.ただ,書き方が良いかどうかは微妙すぎるので,よりよい書き方がありましたら,ご指摘下さい.

<IfModule mod_deflate.c>
  DeflateCompressionLevel 9
  DeflateFilterNote Ratio ratio
  LogFormat "%h %l %u %t \"%r\" %>s %b (%{ratio}n%%)" common_deflate
</IfModule>

<IfModule mod_proxy.c>
  Listen xxxxx
  <VirtualHost _default_:xxxxx>
    CustomLog /var/log/apache2/proxy.log common_deflate
    ErrorLog /var/log/apache2/proxy_error.log

    ProxyRequests On
    ProxyVia Block

    <Proxy *>
      Order deny,allow
      Deny from all
      AuthType Digest
      AuthName "ProxyAuth"
      AuthUserFile /etc/apache2/.prxpswd
      Require valid-user
      Satisfy any

      AddDefaultCharset Off
      SetOutputFilter DEFLATE
    </Proxy>

    <IfModule mod_ext_filter.c>
      ExtFilterDefine jpeg-filter mode=output cmd="/usr/bin/convert -quality 15 jpeg:- jpeg:-"
      ExtFilterDefine png-filter mode=output cmd="/usr/bin/convert -colors 16 -colorspace Transparent -quality 90? +dither +profile \"*\" png:- png:-"
      <ProxyMatch \.(jpe?g|JPE?G)$>
        SetOutputFilter jpeg-filter
      </ProxyMatch>
      <ProxyMatch \.(png|PNG)$>
        SetOutputFilter png-filter
      </ProxyMatch>
    </IfModule>
  </VirtualHost>
</IfModule>

参考

Windowsでファイル名が文字化けしないGit

やっとWindowsでファイル名が文字化けしないGitが可能になるっぽいです.いや,今までもできたかもしれないけど.試してみたところ,以下の環境下では,TortoiseGitでファイル名が文字化けせずに扱えました.

素敵ね!

関連

Arduinoはじめました

時代の波に完全に乗り遅れていますが,Arduinoを始めました.

最初,amazonで買おうかと思っていたのですが,アキバに行った方が楽しいとの示唆を受けました.

ですので,アキバで買ってきました.買ってきたのは,LCDと温度センサと湿度センサを組み合わせたキットで,早稲田大学の先生もご利用になられていらっしゃる大変に素晴らしく実績豊かなキットです.中身のArduino本体はArduino Unoっていうかわいいヤツです.

それから,追加でイーサネットシールドを購入しました.これでインターネットができちゃいます!

キットを作るよ

ブレッドボードを使うので,半田ごては必要ありません.ニッパーとラジオペンチくらいは要りますけど・・・.んで,それらを組み合わせて,かっかかつかつと組み立てると簡単に完成です.

簡単ね!でも,実はキット通りじゃなくて,ブザーとかをつけてないのです.なので,LCDの1行目が意味ないので,別の表示になるように遊んでみました.

自分で作っておきながら,実にウザイですwww.

イーサネットも試すよ

実は工学系でありながら,自宅に半田ごてもニッパーもラジオペンチもレンチも万力も定電圧源もスライダックもすべり抵抗器も真空蒸着チェンバーも何もないですが,職場には全部あります.逆に,職場には無線LANはバンバン飛んでるんですが,気軽に使える有線LANがないのです.うへぁ.というわけで,イーサネットを使う実験は職場ではできないので,自宅でやることにしました.

やってみたいこととしては,ネットに繋がるとなったら,やっぱり何が何でもツイッターに発言でしょ.ということで,そのようなライブラリがあるので,使わせてもらいました.イーサネットのライブラリはArduino Ethernetを頂いてきました.では,そのようにして組んでいきましょう.で,組み上がったのですが,どうも上手くいかない.イーサネットを有効にすると,LCDが死んでしまうのです.今まで動いていて,イーサネットを有効にすると死ぬということは,直感的にポートの重複使用でしょう.なので,調べてみたところ,イーサネットシールドがデジタルI/Oの10-13ピンを使うらしく,どう考えてもLCDとバッティングしてます.ということで,渋々LCDは2-9ピンを使うように変更しました.配線を変更した最新版はこんな感じ.

んで,完成したのでつぶやき始めました.

しかし,どうにもこうにもコンソールで見ていると,GAE側の問題で何度かつぶやきに失敗しているようです.うーん.

まとめ

できたんだけど,イーサネットシールドとLCDを同時使用するとデジタルI/Oが全部埋まっちゃうので,新しいおもちゃをつけられない.イーサネットは必須なので,LCDはお蔵入りする方向と思われ.

WordPressのguidはGUIDじゃない

だからパーマリンクの設計はまず最初にやれとあれほど言っただろ(挨拶).ということで,パーマリンク関連ではまったので,愚痴エントリ.解決策もあるよ.

発生した問題

get_posts関数で記事一覧を取得して,その返り値からpost_titleとguidを使ってリンクを作っていたんです.まぁ,問題なく上手くいってました.しかし,ある時(っていうかついさっきだけど)パーマリンク構成を変更しました.そうすると,途端に問題と出くわしました.

どんな状態かといえば,パーマリンクを変更したのに,guidが変わっていないのです.そのため,リンクがあっちこっちでぶっ壊れました.そこで,調べてみたところ,どうもこのguidはパーマリンクではないようなのです.今回のようなパーマリンクの変更だけではなく,ブログを引っ越した際などでドメインが変わった場合も同様の問題が発生するようです.つまり,このguidってのは,記事を指し示すURIにはなってなくて,URIのように見えるだけで,単なるidentifierに過ぎないようなのです.よくよく読んでみると,確かにそのように書いてあります.

It’s merely a unique identifier, which so happens to be a link to the post at present.

Function Reference/get post ≪ WordPress Codex

それ,guid (Global Unique Identifier)っていうか??なんでHTTPなURI表現なんだ??ということで,漫然とguidを使うと,はまります.

解決策

guidは当てにならないので,代替策が必要になります.使えそうなのは,明確にパーマリンクだといっているget_permalink関数です.引数に記事IDを渡すとパーマリンクが返ってくるそうです.ですので,以下のようなコードが有力でしょうか.

$posts = get_posts('numberposts=-1);
foreach($posts as $post) {
  $links[$post->post_title] = get_permalink($post->ID);
}

まぁ,こんなもんですよね.

エントリ名をトリガにしたオートリンクの方法

ブログを長いこと書いていると,エントリ数が膨大になるので,過去に書いた記事を探し出してリンクを張ることが面倒になってきます.エントリ名をトリガにして,テキストをハイパーリンクに置換して,オートリンクすることができれば,便利だなぁなんて思うわけです.ですので,それをWordpressで実現してみます.方法はかなり泥臭い手法です.

前提条件と基本戦略

前提条件を以下のように設定します.

  • エントリ本文に対してオートリンクを行う.
  • エントリ本文は基本的にプレーンテキストである.
  • 置換対象文字列は既存のエントリ名とする.
  • 置換後は既存エントリにハイパーリンクを張る.

上記条件を前提として,オートリンクを実現します.基本的な戦略は以下の通り.

  • 既存エントリ名を全て取得する.
  • エントリ本文から既存エントリ名があるかどうかを探す.
  • もし見つかれば,オートリンクに置換する.

既存エントリ名を全て取得する

これは別に難しくないですね.Wordpressの関数を使って,サクッと作ると,以下のような感じでしょうか.

$posts = get_posts('numberposts=-1');
foreach($posts as $post) {
  $links[$post->post_title] = $post->guid;
}

こんな感じで,$link[]な連想配列にkeyとしてエントリ名,valueとしてパーマリンクが格納されます.簡単ちんね.この辺りは,頻繁に変わらないだろうから,キャッシュを仕掛けるとか,どっかに定数として準備しておいても良いかも.

エントリ本文に既存エントリ名があるかどうかを探す

では,文字列置換をしましょう.PHPで文字列置換といえば,str_replaceですが,単純に使うとマズイです.以下のような例を想定しましょう.

私はコーヒーよりもコーヒー牛乳が好きです.

ここで,既存エントリとして「コーヒー」および「コーヒー牛乳」があったとします.置換順序が「コーヒー」「コーヒー牛乳」だった場合,以下のように置換されて行きます.ここでは,マッチした部分を強調で示します.

私はコーヒーよりもコーヒー牛乳が好きです.

次に「コーヒー牛乳」で置換したいのですが,既に「コーヒー」で置換されているので,マッチしません.マズイですね.ですので,置換文字列は,文字数が多い順に並んでいる必要性があると思います.そうすることで,最長一致による文字列置換が実現されます.では,それだけでよいでしょうか?置換順序が「コーヒー牛乳」「コーヒー」の順番になっても,次の問題が発生します.

私はコーヒーよりもコーヒー牛乳が好きです.

この文字列に対して,「コーヒー」の置換を行うと,「コーヒー牛乳」の「コーヒー」が再度置換されます.結果として,入れ子のaタグで挟まれる形になります.これはマズイです.つまり,単純な置換はできないので,正規表現を使うことにしましょう.

正規表現による戦略

mb_ereg_replaceを用います.置換文字列が対象文字列内にあり,さらにaタグで挟まれていない場合に,置換を行いましょう.皆さまご存じの通り,私は正規表現を苦手としており,四苦八苦です.ですので,一生懸命探しました.しかし,結構見つからないのです.出てくるのは,HTMLタグの除去とか,URLっぽい文字列を見つけたらオートリンクで置換とかばっかりです.ちょっと違うのです.しかし,需要がないはずはないと思い,頑張って探したところ,見つかりました.ググリ力は大事ですね!

とりあえず、「aタグの内部には他のタグは含まれていない」という前提の元で話を進めます。

$string = "朝一番のコーヒーは<a href='index.html'>3時のコーヒーや</a>食後のコーヒーより旨い";
$pattern = 'コーヒー(?![^<]*</a>)';
$result = mb_ereg_replace($pattern, '紅茶', $string);
echo $result;

タグにはさまれている文字以外を置換したい – PHP – 教えて!goo

ktkr!これでバッチリです.

functions.phpでフィルターフックをかける

では上記基本検討に従って,エントリ本文を表示する際に,エントリ本文中に既存エントリ名があった場合,オートリンクを張るような仕掛けを作ります.今回は,テーマで使われるfunctions.phpにフィルターフックを仕掛けてみました.対象とするフィルタフックはthe_contentです.つまり,まとめると,以下のようなコードをfunctions.phpに書きます.

function myautolink($content='') {
  mb_regex_encoding('UTF-8');
  $links = array();
  $length = array();

  $posts = get_posts('numberposts=-1');
  foreach($posts as $post) {
    $links[$post->post_title] = $post->guid;
    $length[$post->post_title] = mb_strlen($post->post_title);
  }
  arsort($length);

  foreach($length as $link => $val) {
    $pattern = $link.'(?![^<]*</a>)';
    $replacement = '<a href="'.$links[$link].'">'.$link.'</a>';
    $result = mb_ereg_replace($pattern, $replacement, $content);
    if(false != $result) {
      $content = $result;
    }
  }
  return $content;
}
add_filter('the_content', 'myautolink');

簡単ね!

まとめ

エントリ数が膨大だったり,置換対象の文章が長い場合には,性能が低下する可能性が高くなるので,キャッシュを準備するとか,なんかそういう工夫が必要になります.それについて,今回は触れないので,必要があれば工夫して下さい.

1 / 212

Home > タグ > programming

アフィリエイト

Return to page top