実験日記

WORDPRESSでレスポンシブする場合に注意!

現在、WORDPRESSには沢山のレスポンシブテーマが用意されており、これを使うと簡単にレスポンシブル対応ができてしまいます。しかしオリジナルで追加したコンテンツが簡単に変換されてレスポンシブ表示になるかと言えばそんなことはありません。

一番問題になりそうなところを言ってしまうと、テーブルタグ、divタグの入れ子にした時が最も崩れてしまう可能性があります。

レスポンシブは手法を大きく分けると3種類存在します。

  1. 従来の技術リキッドレイアウト(CSSのautoやHTMLの%表示指定などをフル活用)
  2.  

  3. Javascriptやプログラム側でUSER_AGENTからブラウザ判定しstyle.cssを切り替える
  4. JQuery等のJavascript系のライブラリーを使用する

で、実際3番を最初やってみましたよ。

ところが問題がありました。
JQueryのライブラリーは当然WORDPRESSを入れると最初から自動で入っていますし、テーマがレスポンシブル対応であれば尚更、補足するライブラリーが沢山詰まっているわけですよ。

結局コンタクトフォーム、テーブル表示、DIVタグ入れ子の箇所はレスポンシブダメダメでとほほだったのでJQueryやその他のJavascriptライブラリーを入れてみたが、どうやら干渉してしまい、まともに動きません。

大体の予測はありました。AjaxライブラリーをWORDPRESSに導入した場合も、プログラムの”$”の箇所を”JQuery”に書き換えて対応したので、おそらく其の関連であろうと思います。しかし書き換えるのも面倒なのでJavascriptさよならしました。
一般的にはWORDPRESSの最初から同梱しているものを外して、オリジナルのJQueryを入れると動作するものと思われます。

んで、原点に戻りリキッドレイアウトを利用し結局作らわざるを得なかった。
成功例があれば、こっちの方はそれほど難しくないということがわかった。IEでうまく表示できない場合はリキッドレイアウトの方がそもそも対応しやすいと思う。また2番めの手法も合わせて利用すると完璧かもしれない。

WordPressセキュア&SPAM制限TIPS

最近、様々なプロバイダーでCMSを使ったコンテンツが侵略され改竄される被害にあっています。全て同じ手法で攻撃されているわけではありませんが、必要十分なセキュリティについて掲載して行きたいと思います。

一番、ガンブラー系攻撃でブロックする有効な手法はIPアドレスのフィルタリングではないでしょうか?
自宅のアクセスライン、会社のアクセスラインに固定IPのインターネットサービスを使う必要があります。固定IPのアクセスラインは安いところもありますのでそれを活用すると良いと思います。

もしどうしても、固定IPがとれないならProxyServerを格安VPS上で動作させてあげれば、VPSの固定IPを使ってブラウザーアクセスすればIPの固定化ができます。私の会社の顧客の一部もそうしています。日本には昔からよく知られたProxyServerでDelegateというオープンソースサーバがあります。これを使ってブラウザーのProxyServer設定を組み込んで自社のHPへアクセスする際に制限をかければ問題ありません。

http://www.delegate.org/delegate/

話は戻って実際にIPアドレスでの制限をかける設定ですが以下の記述をApache Web Serverにかけてあげれば安全です。
記述する箇所はhttpd.confやvirtual.conf等のディレクティブとディレクティブで利用してください。又.htaccessにも記述しても動作いたします

アクセス制限サンプル

order deny,allow
allow from a.b.c.d # ここに許可するアクセスIPを記述。
deny from all

ホットリンクを制限します

ホットリンクとは自分のコンテンツを勝手に他サイトで利用されることを意味します。いい意味でリンクされるなら視聴の営業活動になるのですがSEO上、アクセス負荷上の問題となることもあるので制限をかけたい人はいるはず
下記は画像を勝手にリンクされてしまうのを防ぐ例です。ページ全体のリンクも下記応用でフィルタリング可能です
手法はアクセス前のリファラーを見て自サイト経由からのアクセス以外は自動で警告(warn_stolen_image.jpg)イメージに転送する記述です。apacheのhttpd.conf.virtual.confや.htaccessに記述してください。

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example.com/.*$ [NC]
RewriteRule \.(gif|jpg)$ http://exampe.com/warn_stolen_image.jpg [R,L]

コメントスパムをブロックします

ブログコメントにスパムをする輩って多いですよね。これをブロックするためにリファラーを監視します。
リファラーはどのページから該当ページを見に来たのか、一つ前にいたページをチェックする機能です。
スパムのプログラムはダイレクトにコメントプログラムへアクセスするため基本Noリファラーになります。
ノーリファラーできたものは自身へ転送します。つまりエラーになります。apacheのhttpd.conf.virtual.confや.htaccessに記述してください。

RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER} !.*example.com.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]

wp-config.phpをアクセス禁止

アクセス制限サンプルと同じ要領で行なってください。apacheのhttpd.conf.virtual.confや.htaccessに記述してください。

<Files wp-config.php>
order allow,deny
deny from all
</Files>

.htaccessのアクセス禁止

apacheのhttpd.conf.virtual.confや.htaccessに記述してください。

<Files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
satisfy all
</Files>

.htaccessのファイル名を変更して攻撃者からapacheコンフィグを探せなくする

.htaccessファイル自体の名前は知られているので別のファイルの名前にすると安全です。apacheのhttpd.conf.virtual.confに記述してください。
次からはht.access.ruleが.htaccessの代わりとして動作します。

AccessFileName ht.access.rule

以上ですが、是非トライしてみてください。

Python Bottle Framework + Twitter BootStrap + MySQL ベース環境

いろいろな開発で利用できるPython Bottle Frameworkの初期開発環境パッケージを作ってみた。Apache WEBサーバで動作するように作成していますのでご参考ください。Bottleは使った感じがFlaskに似ています。Flaskを使っていた時期もありましたが今はBottleをメインで使っています。

そもそも毎回環境作っていると面倒くさいので最低限の機能をまとめてみました。
ワタシ的には、WEBシステムの開発依頼を受けるとほとんどは、Python Bottleで間に合っています。まれに規模が大きい時はPyramidを使う時はありますが割合的にはPyramidを使うのは2割程度で8割がBottleです。Bottleに必須で足りないのは認証とPagerとメールくらいです。これが揃えば簡単に短期間でプロトタイプが作れます。たまに事情的にPHPで仕事依頼を受ける時がありますが、結構嫌です。といっても結構PHPの割合は依然多いです。やはりPHPのほうがコードの解読性が良くないのでそこが開発上嫌なとこかな。

ページは必要最低限のものしか入っていません。login認証、トップ画面、管理画面パネルのみです。
他の進んだフレームワークのように管理画面のパネルが一気にCRUD機能を自動生成するところまではやっていないので、管理画面は水平メニューしかありません。
ただし、ORM使って簡単にデータ操作行えば管理画面は簡単に作れると思うので皆さん自作してみてください。ここまでbottleの動作ができていればbottle frameworkを使った開発は難しくありません。

Python Framework + Twitter BootStrap + MySQL ベース認証で動作します。認証はわざと難しく作っていませんので自分のアイデアで拡張・改造してみてください。

ユーザ認証はlogin:test@example.com  password:admin01 のデータがデモ用で入っています。
直接DB操作でユーザ登録を行なってください。MySQLで登録する際、MD5関数でパスワードを登録してください

Bottle,Beaker,SQLObjectはeasy_install やpipで落としてください。

同梱物)

Apache Config File –  wsgi-bottle.conf

adapter.wsgi – wsgi with apache interface

index.py –  framework top program

bottle_db.sql –  mysql  db sql create file

Twitter Bootstrap –  css/  js/ img/  view/main.tpl

その他 –  基本プログラム&ファイル

 

Dwonloadはここをクリック

Python Bottle&Cork サンプルPG

Pythonのbottle.pyというフレームワークがありますが、なかなかわかりやすく使いかってが良いのでご紹介します。
下記はWEBで自分のサイトのランクを調べるプログラム。ログインして条件入力するページへ飛び検索開始すると1分ぐらいで順位を表示します。

あらかじめbottle,bottle-cork,google,BeautifulSoup,Beakerをpipもしくはeasy_installで入れておくこと。
bottle-corkはbottleのセッション管理モジュール。あまり詳しい情報が本サイトを見てもないのでソースコードを見るのが一番わかりやすい。

尚、プログラムはadapter.wsgiを使ってApache WEBサーバと連携するようにしてください。

必要とするPGファイル

  • adapter.wsgi
  • index.py
  • admin.py
  • rank.py
  • login.py
  • make_conf.py

テンプレート(views)

  • index.tpl
  • login_form.tpl

staticファイル(static)

  • css/style.css
  • js/protoypr.js
  • js/rankget.js

confファイル(conf)

  • register.json
  • user.json
  • roles.json
adapter.cgi
# -*- coding:utf-8 -*-
import sys, os ,bottle
dirpath = os.path.dirname(os.path.abspath(__file__))
sys.path.append(dirpath)
os.chdir(dirpath)
from index import app
application = app
rank_get.js
function ajaxReq(url){
         var p1 = document.js.url.value;
         var p2 = document.js.keywords.value;
         var p3 = document.js.number.value;
         var para = new String();
         para += '&url=';
         para += p1;
         para += '&keywords=';
         para += p2;
         para += '&number=';
         para += p3;
         new Ajax.Request(url, {
                          method: "get",
                          parameters: para,
                          onSuccess:function(httpObj){
                          $("result1").innerHTML = httpObj.responseText;
                          $("result2").innerHTML = httpObj.responseXML;
                          },
                          onFailure:function(httpObj){
                          $("result1").innerHTML = "エラー及び取得順位ゼロが要因で読み込めませんでした";
                          }
                                });
     }

     Ajax.Responders.register({
         onCreate: function() {
         Element.show($('loading'));
     },

     onComplete: function() {
         Element.hide('loading');
         alert('complete');
     }
    });

   Event.observe(window, 'load', function() {
      Element.hide('loading');
    }, false);
make_conf.py
#!/usr/bin/env python
#
#
# Regenerate files in example_conf

from datetime import datetime
from cork import Cork

def populate_conf_directory():
    cork = Cork('conf', initialize=True)

    cork._store.roles['admin'] = 100
    cork._store.roles['editor'] = 60
    cork._store.roles['user'] = 50
    cork._store.save_roles()

    tstamp = str(datetime.utcnow())
    username = password = 'admin'
    cork._store.users[username] = {
        'role': 'admin',
        'hash': cork._hash(username, password),
        'email_addr': username + '@localhost.local',
        'desc': username + ' test user',
        'creation_date': tstamp
    }
    username = password = 'guest'
    cork._store.users[username] = {
        'role': 'user',
        'hash': cork._hash(username, password),
        'email_addr': username + '@localhost.local',
        'desc': username + ' test user',
        'creation_date': tstamp
    }
    cork._store.save_users()

if __name__ == '__main__':
    populate_conf_directory()
rank.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from google import search
from BeautifulSoup import BeautifulSoup
import urllib

class webRank(object):
      def __init__(self):
          self.lang = 'ja'

      def search(self,domain,mysite,words,st0,st1):
          cnt = 1
          for url in search( words ,tld=domain, lang=self.lang,start=st0, stop=st1):
                soup = BeautifulSoup(urllib.urlopen(url))
                if url.find(mysite) != -1:
                       try:
                           title =  soup.find('title').string
                       except:
                           title = ""
                       #return str(cnt) + u"位" + url + "  " + title
                       return [str(cnt),url,title]
                cnt += 1
admin.py
import bottle
from beaker.middleware import SessionMiddleware
from cork import Cork
from login import *

@bottle.route('/admin')
def admin():
    """Only administrators can see this"""
    aaa.require(role='admin', fail_redirect='/sorry_page')
    return 'Welcome administrators'

@bottle.route('/register', method='POST')
def register():
    """Users can create new accounts, but only with 'user' role"""
    username = request.POST.get('user', '')
    password = request.POST.get('pwd', '')
    email_addr = request.POST.get('email_addr', '')
    aaa.register(username, password, email_addr)
    return 'Please check your inbox.'
~
login.py
import bottle
from beaker.middleware import SessionMiddleware
from cork import Cork

# Setup Beaker middleware to handle sessions and cookies
app = bottle.default_app()
session_opts = {
        'session.type': 'cookie',
        'session.validate_key': True,
}
app = SessionMiddleware(app, session_opts)

# Use users.json and roles.json in the local example_conf directory
aaa = Cork('conf')

@bottle.route('/login', method='POST')
def login():
    username = bottle.request.POST.get('user', '')
    password = bottle.request.POST.get('pwd', '')
#    return username,password
    aaa.login(username, password, success_redirect='/', fail_redirect='/login')

@bottle.route('/login')
@bottle.view('login_form')
def login_form():
    """Serve login form"""
    return {}

@bottle.route('/logout')
def logout():
    aaa.logout(success_redirect='/login')

@bottle.route('/sorry_page')
def sorry_page():
    """Serve sorry page"""
    return '<p>Sorry, you are not authorized to perform this action</p>'
index.py
# -*- coding: utf-8 -*-
import bottle
from bottle import route, request, response, template,static_file
from beaker.middleware import SessionMiddleware
from cork import Cork
from rank import webRank
# Setup Beaker middleware to handle sessions and cookies
app = bottle.default_app()
session_opts = {
        'session.type': 'cookie',
        'session.validate_key': True,
}app = SessionMiddleware(app, session_opts)
# Use users.json and roles.json in the local example_conf directory
aaa = Cork('conf')

from login import *
from admin import *

@route('/static/<filepath:path>')
def static(filepath):
    return static_file(filepath, root="./static")

@bottle.route('/')
@bottle.view('index')
def index():
    """Only authenticated users can see this"""
    aaa.require(fail_redirect='/sorry_page')
    return {}

@bottle.route('/rank', method="GET")
@bottle.view('web_rank')
def rank():
    """Only authenticated users can see this"""
    aaa.require(fail_redirect='/sorry_page')
    web = webRank()
    words = bottle.request.GET.get('keywords', '')
    url = bottle.request.GET.get('url', '')
    stop = bottle.request.GET.get('number', '')
    result = web.search("co.jp",url,words,1,int(stop))
    return {'url':result[1],'title':result[2],'rank':result[0]}

# Web application main

def main():

    bottle.debug(True)
    # Start the Bottle webapp
    bottle.run(app=app,host="0.0.0.0", quiet=false, reloader=True)

if __name__ == "__main__":
    main()
login_form.tpl
<!doctype html>
<html lang="ja">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
</head>
<body>

  <div class="login_box">
      <h2>管理ページログイン</h2>
      <p>ログイン項目を入力してください</p>
      <form action="/login" method="post" name="login">
          ログイン&nbsp;&nbsp;&nbsp:<input type="text" name="user" /><br>
          パスワード:<input type="password" name="pwd" /><br>
          <button type="submit" name="submit" > LOGIN </button>
          <button type="button" class="close"> CANCEL </button>
      </form>
  </div>

</body>
</html>

WORDPRESSからAjaxでPythonへリクエスト。DBデータをJSON形式にしてAjaxへ返却

Python WSGI SCRIPTで依頼元からAjax経由でJSONで受取り、DBから引用したデータをJSONデータにして返却するサンプル。呼び出し元はWordPressなどでAjax記述で呼び出して、コールバックしたものをWordPressに表示する。尚、DBはSQLObjectのORMapperを利用しています。

WORDPRESSの固定ページ、記事に直接Javascriptを記述できないのでプラグインを導入して利用できるようにします。
尚inline-jsと言うプラグインを使用しています。
このプラグインを導入します

WORDPRESSで呼び出すAjax

[inline]
[script type="text/javascript"]
jQuery(function(){
  jQuery('#get_search_json').click(function(){
    var data = jQuery("#job").val();
    var url = '/search/get_jobs';
    jQuery.getJSON(url,
          { 'job': data }, 
          function(data){
           for(var i in data){
               for( var key in data[i]){
                    jQuery('#result').append(jQuery('<p>').html(key +': '+ data[i][key]));
               }
               jQuery('#result').append("<hr>");
           }
    });
  });
});
[/script]
[/inline]



JOBの種類:<input type="text" id="job" />
<button id="get_search_json">JOB検索</button>
<div id="result" style="border: 2px solid #595">
[結果出力]
</div>

Ajaxで裏側で呼び出すAPI(WSGI SCRIPT)  url:/search/get_jobs – index.wsgi

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import cgi
from sqlobject import *
import datetime
import json
import pprint
sqlobject_encoding="utf8"
#SQLObjectのバグでURLにcharsetをつけないと日本語コードが文字化けする。
sqlobject_url = "mysql://xxxx:xxxxxxxxxxxxxxxxx@localhost/nms_test?charset=%s" % sqlobject_encoding
sqlhub.processConnection = connectionForURI( sqlobject_url )

class Jobs(SQLObject):
      class sqlmeta:
        table = "jobs"
        fromDatabase = True

def application(environ,start_response):
      query = cgi.parse_qs(environ.get('QUERY_STRING'))
      status = '200 OK'
      response_headers = [('Content-type', 'application/json;charset=utf8')]
      listdat = []
      i = 0
      for b in  Jobs.select( Jobs.q.jobcategoryAlias == query['job'][0] ):
          if i > 4:
             break
          json_data ={'id':b.id,
                      'catch_copy':b.catchCopy,
                      'jobcategorysummary':b.jobcategorysummary,
                      'profile':b.mysummary,
                      'work_history':b.worksummary,
                      'requirement':b.description,
                      'position':b.position
                     }
          listdat.append(json_data)
          i += 1

      start_response(status,response_headers)
      data = json.dumps(listdat,indent=7,ensure_ascii=False )
      return data

WSGI SCRIPTのApache Web Serverへの設定

スクリプトは/etc/httpd/conf.d/wsgi.confへ以下のように追記します

LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias /search/get_jobs /var/www/vhosts/wp2.alpscd.co.jp/index.wsgi

WP/MT の高速化

WordPressやMovableTypeを使っていて遅いと感じること多いですよね。

こんな時に便利なのがキャッシュプラグインなのですが、キャッシュにはメモリのキャッシュとファイルのキャッシュがあります。
WordPressでは色々なキャッシュプラグインがありますが、基本ファイルキャッシュのプラグインが多いです。WPやMT混在で存在するなら

メモリー上で動作するキャッシュが早くてよいと思います。

有名なところでmemcachedが国内でも非常によく使われています。

まず最初にWPのケース

キャッシュサーバ導入
# yum install –enablerepo=rpmforge memcached <----rpmforgeのレポジトリが必要。 PHPキャッシュモジュール導入 # pecl install memcache PHPにモジュール組み込む # vi /etc/php.d/memchached.ini ; for memcache extension=memcache.so # service httpd restart # service memcached start 今度はWPの管理コンソールに入り、プラグインを新規追加から「Memcached Object Cache」をインストール。 ただしインストールした後に、pulguin/memcachedフォルダーからwp-content直下に object-cache.phpファイルを移動させてください。 これをしないと動作しません。 これでWPにmemcachedが設置されました。サイトが真っ白になるようであればWEBサーバを再度起動させてください。もしくはmemcacheモジュールが phpにうまく設置できていない可能性があります。

MTのケース

yumでmemcachedサーバをインストールするのはWPと全く同じです。

# cpan -i Cache::Memcached

# vi mt-config.cgi  <---最下部に以下を追加記述 MemcachedServers 127.0.0.1:11211 # service httpd restart <---本来CGIなので再起動いらないと思うが念のため。 # service memcached restart 以上で完了。サイトにアクセスするとキャッシュが効いています。 一通リのページに自分でアクセスしキャッシュを適用させておきましょう。

WordPressのメール送信フォーム Contact Form7のカスタマイズ

WordPressのメール送信フォームのカスタマイズで有名なContact Form7は有名ですが、このカスタマイズにはしばらく手を出していなかった。

今回必要となる要件としてWordPressのユーザ(WPをつまり会員サイト用につくる)した時にメール送信フォームを
用意する場合、どうやってユーザ名とメールアドレスを自動で入れるかが課題だった。既に会員登録しているから入力させるのは
重複なわけだ。

検索したところ、ようやくContact Form7でそれがサポートされていることがわかった。
このサイトが役に立ちました。


ログインフォームの自動化(本家サイト)

ちなみに、下記も一緒に読むとベスト
[WordPress] ユーザー情報を取得する
特別なメールタグ

インストール: 久しぶりにRED5ストリーミングサーバ 構築

以前のサイトでは、RED5で作るストリーミングサーバの記事が大変人気だったため、このサイトに変えて無くなってしまったため、困っている人が多いようだ。

ということで少し記事を復活させよう。

# 適当なフォルダーつくってRED5ダウンロード
# wget http://red5.org/downloads/red5/1_0/red5-1.0.0-RC2.tar.gz

# tar xvfz red5-1.0.0-RC2.tar.gz

# ls
red5-1.0.0 red5-1.0.0-RC2.tar.gz

# cd red5-1.0.0

ファイルは以下のようになっている
# ls -l
合計 2036
-rw-r–r– 1 root games 409 5月 17 01:36 2012 Makefile
-rw-r–r– 1 root root 36864 7月 25 01:16 2013 admin.h2.db
-rw-r–r– 1 root games 16493 5月 17 01:36 2012 boot.jar
-rw-r–r– 1 root games 1850 5月 17 01:36 2012 build.properties
-rw-r–r– 1 root games 45769 5月 17 01:36 2012 build.xml
drwxr-xr-x 3 root games 4096 7月 14 09:16 2013 conf
drwxr-xr-x 8 root games 4096 5月 17 01:36 2012 doc
drwxr-xr-x 2 root games 4096 5月 17 01:36 2012 lib
-rw-r–r– 1 root games 1284 5月 17 01:36 2012 license.txt
drwxr-xr-x 2 root games 4096 7月 25 01:06 2013 log
drwxr-xr-x 2 root games 4096 5月 17 01:36 2012 plugins
-rw-r–r– 1 root games 168 5月 17 01:37 2012 red5-debug.bat
-rwxr-xr-x 1 root games 220 5月 17 01:37 2012 red5-debug.sh
-rw-r–r– 1 root games 1181 5月 17 01:37 2012 red5-highperf.bat
-rwxr-xr-x 1 root games 417 5月 17 01:37 2012 red5-highperf.sh
-rw-r–r– 1 root games 308 5月 17 01:37 2012 red5-shutdown.bat
-rwxr-xr-x 1 root games 344 5月 17 01:37 2012 red5-shutdown.sh
-rw-r–r– 1 root games 1110 5月 17 01:37 2012 red5.bat
-rw-r–r– 1 root games 963323 5月 17 01:37 2012 red5.jar
-rwxr-xr-x 1 root games 1297 5月 17 01:37 2012 red5.sh
-rw-r–r– 1 root games 930294 5月 17 01:37 2012 src.zip
drwxr-xr-x 8 root games 4096 7月 14 09:20 2013 webapps
drwxr-xr-x 3 root root 4096 7月 14 09:09 2013 work

起動はすごい簡単次のファイルを起動するだけ。
# ./red5.sh &

もし、Javaを導入していなければダウウロードしていれましょう。
http://docs.oracle.com/javase/7/docs/webnotes/install/linux/linux-jdk.html
JDK 7導入方法は省略。

今回は擬似ストリーミングではなくて本物のRTMPプロトコルのストリーミングです。

ストリーミング実現には大きく3種類あり、以下のような感じです。

  • ダウンロード型 (世間一般のWEBサーバに配置するタイプ)
  • 擬似ストリーミング型 (Youtube, GYAO)
  • ストリーミング型 (USTREAM)

違いがわからないと思いますが、ダウンロード型は設備もソフトも特にいらないコンテンツ記述だけでいける方式ですが
閲覧者のブラウザにファイルすべてダウンロードしてから再生するので時間がかかります。またスライダーを動かしても
タイムゲージ(早送り)うごきません。最初から再生して行かないとダメなんです。あと同時にVIDEOダウンロードする人が多いと
サーバがダウンします。精々同時アクセス10人くらいかな。再生はオンデマンドになります。

擬似ストリーミングは、従来のダウンロード型を改善したもので、ダウンロードをちょろちょろ行いながら再生します。スライダー
も動画に予めポジショニングのタグを埋め込むと早送りが可能です。サーバはApache,Lighthttpdなどで行います。これも再生は
オンデマンドになります。同時アクセス20人から50人くらいまでならOK。後はサーバ構築の腕次第でもっといきます。

ストリーミングはリアルタイム録画&再生、オンデマンドをこなす方式です。パケットを逐次ちょろちょろ転送するので沢山の
同時閲覧者をさばく事ができます。100人から500人は余裕かな。

では、次に設定ファイルをいじります。

# vi conf/red5.properties
# RTMP
rtmp.host=192.168.1.150 rtmp.port=1935 <—運用ポートなんでも結構
rtmp.io_threads=16
rtmp.send_buffer_size=271360
rtmp.receive_buffer_size=65536
rtmp.ping_interval=1000
rtmp.max_inactivity=60000
rtmp.max_handshake_time=5000
rtmp.tcp_nodelay=true
rtmp.default_server_bandwidth=10000000
rtmp.default_client_bandwidth=10000000
rtmp.client_bandwidth_limit_type=2
rtmp.bandwidth_detection=true
rtmp.encoder_base_tolerance=5000
rtmp.encoder_drop_live_future=false

VIDEOコンテンツを配置します. flv形式、mp4形式が使えます。
HandBrakeというオープンソースで変換や調整を行ってください。
変換がおわったら、FTP等でアップロードを下記パスへ行います。
# pwd
/opt/red5/red5-1.0.0/webapps/vod/streams
[root@site-wild streams]# ls -la
astro.mp4 street_of_fire.flv street_of_fire.flv.meta

これで準備は整いました。
red5のTOPへ戻り起動します。
# ./red5.sh &

すごい簡単でしょう!

ただね。コンテンツはデリバリー状態に成っているけども、コンテンツの書き方がわからないと提供していないも同然です。
適当なWEBサーバのドキュメントフォルダに再生用のコンテンツを配置して、VIDEOデリバリーできるようにします。

RTMPの再生パスは
このじょうたいでは “rtmp://xxxxxxx.com/vod”と成っています。

JW Playerという有名な無料の埋め込み式Flash Video Playerがあります。これを使います。
このPlayerは擬似ストリーミングとストリーミングの両方に対応しています。
http://www.longtailvideo.com/

以下埋め込みのサンプルコードです。

JW PLAYER (JW Player OLD Player)

<div id="preview" style="float:left;">
Street Of Fire Movie Trailer 1984
</div>

<script type='text/javascript'>
var s1 = new SWFObject('../player-viral.swf','ply','470','320','9','#ffffff');
s1.addParam('allowfullscreen','true');
s1.addParam('allowscriptaccess','always');
s1.addParam('wmode','opaque');
s1.addVariable('id','ply');
s1.addVariable('backcolor','3333FF');
s1.addVariable('lightcolor','00CC00');
s1.addVariable('screencolor','99FFFF');
s1.addVariable('icons','false');
s1.addVariable('dock','true');
s1.addVariable('displayclick','fullscreen');
s1.addVariable('file', 'street_of_fire.flv');
s1.addVariable('streamer', 'rtmp://xxxxxxxx.com/vod');
s1.addVariable('type', 'rtmp');
s1.write('preview');
</script>

JW PLAYER HTML5 fallback flash(JW Player New Player)

<div id='my-video'></div>
<script type='text/javascript'>
    jwplayer('my-video').setup({
        file: 'rtmp://yourserver/vod/spygame.mp4',
        width: '470',
        height: '320'
    });
</script>

fladance player

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="470" height="320" id="ASTRO BOY">
	<param name="flashvars" value="fms_app=rtmp://xxxxxxxx.com/vod/&video_file=michael_say.flv&image_file=&link_url=&autoplay=false&mute=false&vol=&controllbar=true&buffertime=10" />
	<param name="allowfullscreen" value="true" />
	<param name="movie" value="./fladance.swf" />
	<embed src="./fladance.swf" width="470" height="320" name="ASTRO BOY" allowfullscreen="true" flashvars="fms_app=rtmp://html5.spazo.jp/vod/&video_file=michael_say.flv&image_file=&link_url=&autoplay=false&mute=false&vol=&controllbar=true&buffertime=10" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>

PythonでFeedを取ろう!

PythonでWEB作るなら、もちろんFeedを引っ張ることでしょう。NEWSとかTOPICSとか
ということで必要最低限の情報を取り出すコードを下記へペースト。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import feedparser
import time

fd = feedparser.parse('FEED URIパス')

#サイト名を表示
print fd.feed.title

#記事タイトルとリンクURL、日付、概要を表示
for i in range(10):
  print fd.entries[i].title
  print fd.entries[i].link
  print fd.entries[i].published
  print fd.entries[i].summary

#最新記事の更新時間
updatetime = time.strftime('%Y/%m/%d %X',fd.entries[0].published_parsed)
print updatetime

Python WEBアプリをCGIで使う(後編:Part2)

今回は、Twitterのショートプログラムを作って見よう。

PythonでTwitterプログラムを作る時に便利なのがTweepy。
Twitter はREST API v1.0の頃と今は違って仕様が変わっています。巷にあふれているサンプルコードは動作しないものばかりです。動作するものはREST API v1.1に対応したtweepyが必要。
ところが、これがまた不完全で使えない機能が結構ある。

本家のtweepyが糞で使えない。一部対応しているが特に検索機能はだめ!
フォークしたtweepyを”sakito”さんが作ってるのでそれをインストールします。
https://bitbucket.org/sakito/tweepy/src/4e1704b3e391?at=default

Twitter検索の仕様)
https://dev.twitter.com/docs/api/1.1/get/search/tweets

Twitter application keyの取得)
ログインしてアプリケーション登録するとキーが取得出来ます。
https://dev.twitter.com/

hgを使ってローカルに取り込みます。まずはhgがないと話にならない。
# yum install python-devel
# easy_install -U mercurial
# hg clone https://bitbucket.org/sakito/tweepy
# cd tweepy
# python setup.py install

はい、これで使えるようなりました。

検索プログラムで特定のTweetを引っ張りましょう。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os.path
import tweepy2
import urllib

CONSUMER_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
CONSUMER_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
ACCESS_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# Twitter の認証を行う
auth = tweepy2.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
api = tweepy2.API(auth)

def main():
# 検索
    query = u"犬" # クエリ
    results = api.search_tweets(urllib.quote_plus(query.encode('utf-8')))

    print "Content-Type: text/html;charset=utf-8"
    print
#    print "Content-Type: application/octeat-stream"
#    print ""
    print
    print
    print "<html>"
    print "<body>"

    for result in results:
         print str(result.created_at) + "<br>"
         print result.user["name"].encode('utf-8') + "<br>"
         print result.text.encode('utf-8') + "<br>"
         print "-----------------------------------------------------------------------------------------<br>"
    print "</body>"
    print "</html>"
    print ""

if __name__  ==  '__main__':
    main()