Chapter 14: その他のレシピ

その他のレシピ

アップグレード

upgrades

管理者インターフェースの"site"ページには、"update now"があります。実行できないか、動作しない場合 (例えば、ファイルロック問題のため)、web2pyの手動アップデートはとても簡単です。

単に、新しいweb2pyを古いインストレーションへ解凍するだけです。

admin, examples, welcomeアプリケーションだけでなくライブラリも全てアプグレードします。それは、新しい空の"NEWINSTALL"ファイルを生成します。再起動時に、web2pyは、空のファイルを消去し、welcomeアプリケーションは、新しい雛形アプリケーションとして使われる"welcome.w2p" の中に格納されます。

web2pyは、他のファイルや既存のアプリケーションをアップグレードしません。

バイナリでアプリケーションを配布する方法

web2pyのバイナリ形式の配布と一緒に独自のアプリケーションを同梱し配布できます。web2pyをバンドルしている事をアプリケーションのライセンスに明確に記載している事、そしてweb2py.comへのリンクを追記していれば、web2pyのライセンスはこれを許可します。

ここにWindows用の配布方法を説明します:

  • いつも通りあなたのアプリを製作
  • adminを使い、アプリケーションをバイトコードにコンパイル (1クリック)
  • adminを使い、コンパイル済みアプリケーションをパック (もう1クリック)
  • "myapp"フォルダを生成
  • Windows用のweb2pyバイナリ配布をダウンロード
  • それを"myapp"フォルダに解凍し、起動 (2クリック)
  • adminを使いパックされたコンパイル済みアプリケーション名"init"をアップロード (1クリック)
  • "cd web2py; web2py.exe"と書かれた"myapp/start.bat"ファイルを作成
  • あなたのアプリケーション用のライセンスと、"distributed with an unmodified copy of web2py from web2py.com"である明言に念を押させることを含んだ"myapp/license"ファイルを作成
  • myappフォルダを"myapp.zip"ファイルに圧縮
  • "myapp.zip"を配布及び/または販売

ユーザーが"myapp.zip"を解凍し"run"をクリックしたときに、"welcome"アプリケーションの代わりにあなたのアプリケーションが起動します。ユーザーは事前にPythonをインストールする必要さえありません。

Mac用のバイナリを生成する過程も同じですが、"bat"ファイルは要りません。

WingIDE, Rad2Py, Eclipse

WingIDE, Rad2Py, and Eclipse

WingIDE
Eclipse
Rad2Py

WingIDE、Rad2PyやEclipseといったサードパーティのIDEでweb2pyを使用できます。

WingIDEでweb2pyを使った時にスクリーンショットです。

image

これらのIDE(web2pyを向けにデザインされたRad2Pyは除きます)を使った時の一般的な問題として、モデルとコントローラーが実行される状況を理解しないため、そのままでは自動補完が利きません。

自動補完を利かせるための一般的なトリックとして、モデルとコントローラーに次のコードを追加します。

if False:
    from gluon import *
    request = current.request
    response = current.response
    session = current.session
    cache = current.cache
    T = current.T

このコードは全く実行さませんが、IDEに強制的に構文解析させてグローバル名前空間(gluonモジュール)にオブジェクトがどこにあるかを理解させることで、ロジックを変更せずに自動補完を機能させることができます。

SQLDesigner

SQLDesignerという視覚的にweb2pyのモデルの構築や対応するコードの生成をするためのソフトウェアが在ります。これがそのスクリーンショットです。

image

web2pyで動作するSQLDesignerのバージョンは、ここで見れます:

https://github.com/elcio/visualdal

フォルダ公開

web上でフォルダ(サブフォルダも含む)を共有する問題を考えます。web2pyはとても簡単にできます。下記のコードをコントローラに追加するだけです:

from gluon.tools import Expose
def myfolder():
    return dict(files=Expose('/path/to/myfolder'))

{{=files}}でビューに表示できます。ファイルとフォルダを見るためのインターフェースを生成し、ツリー構造でナビゲートします。画像はプレビュー付きです。

"/path/to/myfolder"パスプレフィックスは、訪問者側には隠されます。例えば、"/path/to/myfolder/a/b.txt"というファイルは"base/a/b.txt"に置き換えられます。"base"プレフィックスは、Expose関数のbasename引数の使って指定できます。extensions引数の使用は、ファイル拡張子のリストで指定でき、該当しないファイルは隠されます。例:

def myfolder():
    return dict(files=Expose('/path/to/myfolder',basename='.',
                             extensions=['.py', '.jpg']))

パスに"private"が含まれるファイルやフォルダ、"."で始まるファイルや"~"で終わるファイルは、常に隠されます。

機能テスト(Functional testing)

web2pyは、ローカルとリモートのweb2pyアプリケーションを機能テストするためのgluon.contrib.webclientモジュールを備えています。実は、このモジュールはweb2py向けではなくテストや他のwebアプリケーションと対話するように使えて、さらに、web2pyセッションとweb2pyポストバックを理解するように設計されています。

下記は、使い方です。次のプログラムは、クライアントを生成、 セッションを確立するために"index"アクションへ接続、 新規ユーザの登録、直後にログアウト、再度新たに作ったユーザでログイン:

from gluon.contrib.webclient import WebClient

client = WebClient('http://127.0.0.1:8000/welcome/default/',
                   postbacks=True)

client.get('index')
# register
data = dict(first_name='Homer',
            last_name='Simpson',
            email='homer@web2py.com',
            password='test',
            password_two='test',
            _formname='register')
client.post('user/register', data=data)

# logout
client.get('user/logout')

# login again
data = dict(email='homer@web2py.com',
            password='test',
            _formname='login')
client.post('user/login', data=data)

# check registration and login were successful
client.get('index')
assert('Welcome Homer' in client.text)

WebClientコンストラクタはURLプレフィックスを引数に取ります。例では、"http://127.0.0.1:8000/welcome/default/"となります。他のネットワークIOに対して働きません。postbacks引数はデフォルトでTrueであり、クライアントにweb2pyのポストバックのハンドル方法を通知します。

WenClientオブジェクトclientは、2個だけメソッドがあります: getpost。第1引数は、常にURLポストフィックスを取ります。 POSTリクエストのGET用のフルURLは、プレフィックスとポストフィックスを連消することで簡単に構成しています。 この目的は、クライアントとサーバ間の長いやり取りのためにシンタックスを短くさせることを意味づけています。

dataは、POSTリクエストの明示的なパラメータであり、ポストされるデータのディクショナリを含んでいます。web2pyのフォームは、_formnameフィールドを隠し持っており、ページにたった1つのフォームが存在しない限り提供される値です。web2pyフォームは、CSRF攻撃を弾くために設計された_formkeyフィールドも隠し持っています。WebClientが自動的にフィールドを処理してくれます。

client.getclient.postは他に次の引数をとることができます:

  • headers: 任意のHTTPヘッダーのディクショナリ。
  • cookies: 任意のHTTPクッキーのディクショナリ。
  • auth: BASIC認証を通すためにurllib2.HTTPBasicAuthHandler().add_password(**auth)へ渡されるパラメータのディクショナリです。これに関する詳細は、urllib2モジュールに関するPythonドキュメントを参照してください。

例であるclientオブジェクトは、GETとPOSTリクエストを生成によるコンストラクタで指定したサーバーとの対話を持ち越します。すべてのクッキーを自動的に保持し、セッションを持続するためにクッキーを送り返します。新しいセッションクッキーが既に存在するセッションクッキーであると検知したら、新しいセッションを壊して例外を発生させます。もしサーバーがHTTPエラーを返してきたら、例外を発生させます。サーバーがweb2pyのチケットを含んだHTTPエラーを返したら、チケットコードを含んだRuntimeError例外を返します。

clientオブジェクトは、client.historyにリクエストログを保持し、状態は最新の成功したリクエストで構成されます。状態には下記で構成されます:

  • client.status: ステータスコードを返脚
  • client.text: ページの内容
  • client.headers: パースしたヘッダーのディクショナリ
  • client.cookies: パースしたクッキーのディクショナリ
  • client.sessions: {appname: session_id}からのweb2pyセッションのディクショナリ
  • client.forms: client.textから検知したweb2pyフォームのディクショナリ。{_formname,_formkey}フォームのディクショナリを保持。

サーバーから返されたclient.textをパースする機能はありませんが、BeautifulSoupなどのサードパーティ製モジュールで簡単に実現できます。次のコード例は、クライアントでダウンロードしたページ内のリンクをすべて見つけ、それらを確かめます:

from BeautifulSoup import BeautifulSoup
dom = BeautifulSoup(client.text)
for link in dom.findAll('a'):
    new_client = WebClient()
    new_client.get(a.href)
    print new_client.status

web2pyの最小構成

web2pyをとても小さなメモリ量でデプロイする場合があります。その場合は余分なものをそぎ落とし最小構成にしたいです。

次に簡単な方法を示します:

  • プロダクトマシン上にweb2pyをソースからインストール
  • メインweb2pyフォルダ内で次のコマンドを実行
python scripts/make_min_web2py.py /path/to/minweb2py
  • 次にデプロイしたいアプリケーションを"/path/to/minweb2py/applications"内にコピー
  • "/path/to/minweb2py"を小さなメモリ量のサーバとしてデプロイ

この"make_min_web2py.py"スクリプトは、次の物を含まない最小構成のweb2pyディストリビューションを構築します:

  • admin
  • examples
  • welcome
  • scripts
  • 稼働に不必要なcontribモジュール

デプロイテスト用の1つのファイルから成る"welcome"アプリを含んでいます。このスクリプトを見てください。一番上に、何を含み何が含まれていないかの詳細なリストが書かれています。

外部URLをフェッチ

fetch

Pythonには、URLフェッチするためのライブラリurllibが同梱されています:

import urllib
page = urllib.urlopen('http://www.web2py.com').read()
API

通常は問題ないですが、urllibモジュールは、Google App Engine上では動作しません。Googleは、GAE用に、URLをダウンロードするための異なるAPIを提供します。あなたのコードを移植しやすくするために、web2pyは、他のPython環境だけでなくGAEでも動くfetch関数を同梱しています:

from gluon.tools import fetch
page = fetch('http://www.web2py.com')

便利な日時表現(Pretty dates)

prettydate

日付を"2009-07-25 14:34:56"と表記するのではなく、"one years ago"と表記したほうが良い場合があります。このために、web2pyは便利な関数を提供します:

import datetime
d = datetime.datetime(2009,7,25,14,34,56)
from gluon.tools import prettydate
pretty_d = prettydate(d,T)

出力結果の国際化対応のために第2引数 (T) が渡される必要があります。

ジオコーディング

geocode

住所(例: "243 S Wabash Ave, Chicago, IL, USA")を地理座標(緯度と経度)に変換する必要がある場合、web2pyはそのように動作する関数を提供します。

from gluon.tools import geocode
address = '243 S Wabash Ave, Chicago, IL, USA'
(latitude, longitude) = geocode(address)

geocode関数はネットワーク接続が必要で、ジオコーディング用の Google geocodingサービスに接続します。関数は失敗した場合に(0,0)を返します。Google geocodingサービスはリクエスト回数に上限を定めることに注意し、それらのサービス同意書を確認すべきです。geocode関数はfetch関数上で実装されているためGAEでも動作します。

ページネーション

pagination

このレシピは、ページネーション時にデータベースアクセスを最小化することに役立つ技術です。例えば、データベースから行のリストを表示する必要があるが複数のページにまたがる場合です。

まず、データベースに1000個の素数を1番目から格納するprimesアプリケーションを製作することから始めましょう。

db.pyモデル: Here is the model db.py:

db = DAL('sqlite://primes.db')
db.define_table('prime',Field('value','integer'))
def isprime(p):
    for i in range(2,p):
        if p%i==0: return False
    return True
if len(db().select(db.prime.id))==0:
   p=2
   for i in range(1000):
       while not isprime(p): p+=1
       db.prime.insert(value=p)
       p+=1

そしてこのように、"default.py"コントローラにデータベースを読むlist_itemアクションを作ります:

def list_items():
    if len(request.args): page=int(request.args[0])
    else: page=0
    items_per_page=20
    limitby=(page*items_per_page,(page+1)*items_per_page+1)
    rows=db().select(db.prime.ALL,limitby=limitby)
    return dict(rows=rows,page=page,items_per_page=items_per_page)

このコードは必要な個数より1つ多いアイテムを選択することに注意してください(20+1)。範囲外の要素は次のページがあるかどうかを示します。

"default/list_items.html" ビュー: Here is the "default/list_items.html" view:

{{extend 'layout.html'}}

{{for i,row in enumerate(rows):}}
{{if i==items_per_page: break}}
{{=row.value}}<br />
{{pass}}

{{if page:}}
<a href="{{=URL(args=[page-1])}}">previous</a>
{{pass}}

{{if len(rows)>items_per_page:}}
<a href="{{=URL(args=[page+1])}}">next</a>
{{pass}}

この方法で処理ごとに1つの選択でページネーションができ、1つの選択だけで必要な行だけを選んでくれます。

httpserver.logとログファイルフォーマット

httpserver.log

web2pyのwebサーバーはファイルへのリクエストをweb2pyのルートディレクトに置かれている:

httpserver.log

へ全て記録します。ファイル名やロケーションをweb2pyのコマンドラインオプションを使い指定できます。

新しいエントリーは、リクエストが処理されるたびにファイル末尾へ追加されます。それぞれの行はこのようになります:

127.0.0.1, 2008-01-12 10:41:20, GET, /admin/default/site, HTTP/1.1, 200, 0.270000

フォーマットは:

ip, timestamp, method, path, protocol, status, time_taken

フォーマットは:

  • ipはリクエストしてきたクライアントのIPアドレス
  • timestampはリクエストの日付と時間、ISO8601フォーマット(YYYY-MM-DDT HH:MM:SS)で記述
  • methodはPOSTかGETのどちらか
  • pathはクライアントがリクエストしたパス
  • protocolはクライアントへの送信に使用されたHTTPプロトコル、たいていはHTTP/1.1
  • [status] はHTTPのステータスコード91
  • time_takenはサーバーがリクエストプロセスに掛けた時間の統計、単位は秒、アップロード/ダウンロードにかかる時間は含まれません

アプリケーションのリポジトリ [appliances] から、ログ解析のアプリケーションを利用できます。

このログは、mod_wsgi使用時はApacheログと同じになるため、デフォルトでは有効になりません。

ダミーデータをデータベースに登録

テスト用にダミーデータをデータベーステーブルに登録できれば便利です。この目的に合う読解可能なダミーテキスを学習させたベイズ分類器を、web2pyはすでに含んでいます。

簡単な使い方:

from gluon.contrib.populate import populate
populate(db.mytable,100)

100個のダミーレコードをdb.mytableに挿入します。stringフィールド用の短文、textフィールド用の長文、integer、double、date、datetime、time、boolean、その他のフィールドを知的に生成します。バリデータで指定された必要条件を尊重しようとします。フィールドに単語"name"が含まれているとダミーの名前を生成しようとします。リファレンスフィールドにより妥当なリファレンスを生成します。

もしBがAを参照する2つのテーブル(AとB)があるとき、Aから先に登録し、次にBを登録します。

もしBがAを参照する2つのテーブル(AとB)があるとき、Aから先に登録し、次にBを登録します。

for i in range(10):
    populate(db.mytable,100)
    db.commit()

ベイズ分類器にいくつかの文章を学習させ、学習データと似ているが無意味なダミーテキストを生成できます。

from gluon.contrib.populate import Learner, IUP
ell=Learner()
ell.learn('some very long input text ...')
print ell.generate(1000,prefix=None)

クレジットカード払いの承認

Google Wallet
Paypal
Stripe.com
Authorize.net
DowCommerce

オンラインでのクレジットカードを認証する多様な方法があります。web2pyは、いくつかの有名で実践的なAPIを提供します:

最初2つの仕組みは外部のサービスへの受け取り人を証明するプロセスを上層に委任します。これがセキュリティにとって最良の方法であると同時に(あなたのアプリケーションは全てにおいてクレジットカード情報を取り扱わない)、それは面倒なプロセス(ユーザーは2回ログインする必要がある;例えば、1度目はあなたのアプリケーション、もう1回はGoogleに)を生成しあなたのアプリケーションが自動化された方法で繰り返し支払処理するのを許可しません。

さらなるコントロールが必要な時や自作のクレジットカード情報の入力フォームを生成したい時、すなわち、プログラムがクレジットカードからあなたのアカウントへ送金するための処理を依頼する時があります。

このためweb2pyはStripe、Authorize.Net(モジュールはJohn Condeによって開発され若干修正されています)、DownCommerceとの統合を既定で提供しています。Stripeは最も簡単に使え、低額の売買なら安くすみます(使用料は固定額ではなく取引価格の約3%)。Authorize.netは高額の取引向けです(1年間の定額の使用料が掛かり、加えて1回の取引に安い使用料が掛かります)。

StripeとAuthorize.netの場合、あなたのプログラムがクレジットカード情報を承認することを覚えておいてください。クレジットカード情報を記録する必要はありませんし、我々は法的必要条件が関係するため(VisaやMastercardで取引する場合)あなたにそうすべきでないとアドバイスしますが、何回も会計をしたりAmazon one-clickボタンを再現するためにクレジットカード情報を記録したい場合もあります。

Google Wallet

Google Wallet(Level 1)を簡単に使用する一番の方法は、あなたのページにボタンを埋め込み、そのボタンをクリック時に訪問者をGoogleから提供されている支払いページへリダイレクトする方法です。

まず始めに、あなたはこのURLでGoogle Merchant Accountに登録する必要があります:

https://checkout.google.com/sell

Googleにあなたの銀行口座情報を提供する必要があります。Googleはあなたにmerchant_idmerchant_keyを割り当てます(これらを紛失せず、極秘で保管しておいてください)。

そして、ビューに次のコードを記述します:

{{from gluon.contrib.google_wallet import button}}
{{=button(merchant_id="123456789012345",
           products=[dict(name="shoes",
                          quantity=1,
                          price=23.5,
                          currency='USD',
                          description="running shoes black")])}}

ボタンをクリック時に訪問者は、商品の支払いが可能なGoogleのページへリダイレクトされます。ここでのproductsは製品のリストであり、各製品はあなたが精算したいアイテムを記述したディクショナリ型のパラメータです(name, quantity, price, currency, descriptionや他のオプションの説明はGoogle Walletドキュメントを見てください)。

この仕組みを使用する場合、在庫状況や訪問者のショッピングカートに基づき、buttonへ渡す値をプログラムで生成することもできます。

全ての税金と配送情報はGoogle側で取り扱われます。支払情報も同様です。デフォルトだとあなたのアプリケーションに取引完了されたことは通知されないため、Google Merchantサイトににアクセスし、どの製品が購入され、支払いがされ、どの製品を購入者に届けるべきかを確認する必要があります。Googleはこれらの情報を電子メールでもあなたに知らせてくれます。

しっかりと統合されたものが欲しい時には、Level 2 notification APIを使用するべきです。これを使用した場合、Googleへさらに多くの情報を渡すことができ、Googleは製品購入を通知するためにあなたのAPIを呼びます。このことは、あなたに支払情報をアプリケーション内に保持することを許可しますが、Google Walletと通信可能なWebサービスを公開することをあなたに要求します。

これは難しい処理ですが、そのようなAPIはすでに実装されており、次のURLにプラグインとして公開されています。

http://web2py.com/plugins/static/web2py.plugin.google_checkout.w2p

ドキュメントはプラグイン自身に書かれています。

Paypal

Paypalの統合について、ここでは説明しませんが、このリソースにたくさんの情報があります:

http://www.web2pyslices.com/main/slices/take_slice/9

Stripe.com

これはおそらく最も簡単な方法の1つであり、クレジットカード払いを許可する柔軟な方法です。

Stripe.comに登録する必要がありますが、とても簡単です。実際、Stripはテスト用のAPIキーを認証情報を作成する以前に割り当ててくれます。

一度APIキーを取得しさえすれば、次のコードでクレジットカードを受け付けることができます:

from gluon.contrib.stripe import Stripe
stripe = Stripe(api_key)
d = stripe.charge(amount=100,
              currency='usd',
              card_number='4242424242424242',
              card_exp_month='5',
              card_exp_year='2012',
              card_cvc_check='123',
              description='the usual black shoes')
if d.get('paid',False):
    # payment accepted
elif:
    # error is in d.get('error','unknown')

レスポンスdはディクショナリ型ですので詳細は自分で確認してみてください。例で使われているカード番号はサンドボックスであり、いつも成功します。それぞれの取引はd['id']に格納されたトランザクションIDに関連付けられます。

Stripeは後から取引を照合することもできます:

d = Stripe(key).check(d['id'])

そして取引を返金できます:

r = Stripe(key).refund(d['id'])
if r.get('refunded',False):
    # refund was successful
elif:
    # error is in d.get('error','unknown')

Stripeでアプリケーション内に支払情報を簡単に保持できます。

アプリとStripe間の全ての通信はRESTfulWebサービス上で行われます。Stripeは実際多くのサービスを公開しており、巨大なPython APIセットを提供しています。Stripeのサイトには、よりたくさんの情報があります。

Authorize.Net

もう1つの簡単にクレジットカード承認の方法としてAuthorize.netがあります。いつもどおりあなたは登録する必要があり、loginとトランザクションキー(transaction)を取得します。一度、それらを取得すると、Stripeの様に動作します:

from gluon.contrib.AuthorizeNet import process
if process(creditcard='4427802641004797',
           expiration="122012,
           total=100.0,cvv='123',tax=None,invoice=None,
           login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ',testmode=True):
   # payment was processed
else:
   # payment was rejected

もし有効なAuthorize.Netのアカウントを持っているなら、サンドボックス用のlogintranskeyをあなたのアカウントに置き換え、サンドボックスの代わりに本番のプラットフォーム上で動作させるためtestmode=Falseに設定すべきです。そうすることで訪問者のクレジットカード情報を扱えます。

もし、processTrueを返却したら、訪問者のクレジットカードからあなたのAuthorize.Netアカウントへ送金されたことになります。あなたのプリケーション内でデータと情報を一致させるために、invoiceは、あなたが設定できる文字列であり、このトランザクションでAuthorize.Netにより保持されます。

次のコードは、今までより複雑な、より多くの変数を扱うワークフローの例です:

from gluon.contrib.AuthorizeNet import AIM
payment = AIM(login='cnpdev4289',
              transkey='SR2P8g4jdEn7vFLQ',
              testmod=True)
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows
payment.setParameter('x_cust_id', '1324')       # customer ID
payment.setParameter('x_first_name', 'Agent')
payment.setParameter('x_last_name', 'Smith')
payment.setParameter('x_company', 'Test Company')
payment.setParameter('x_address', '1234 Main Street')
payment.setParameter('x_city', 'Townsville')
payment.setParameter('x_state', 'NJ')
payment.setParameter('x_zip', '12345')
payment.setParameter('x_country', 'US')
payment.setParameter('x_phone', '800-555-1234')
payment.setParameter('x_description', 'Test Transaction')
payment.setParameter('x_customer_ip', socket.gethostbyname(socket.gethostname()))
payment.setParameter('x_email', 'you@example.com')
payment.setParameter('x_email_customer', False)

payment.process()
if payment.isApproved():
    print 'Response Code: ', payment.response.ResponseCode
    print 'Response Text: ', payment.response.ResponseText
    print 'Response: ', payment.getResultResponseFull()
    print 'Transaction ID: ', payment.response.TransactionID
    print 'CVV Result: ', payment.response.CVVResponse
    print 'Approval Code: ', payment.response.AuthCode
    print 'AVS Result: ', payment.response.AVSResponse
elif payment.isDeclined():
    print 'Your credit card was declined by your bank'
elif payment.isError():
    print 'It did not work'
print 'approved',payment.isApproved()
print 'declined',payment.isDeclined()
print 'error',payment.isError()

上記のコードはダミーのテストアカウントを使用していることに注意してください。Authorize.Netに登録(無料ではありません)する必要があり、AIMコンストラクタにlogin、transkeyを渡し、testmode=TrueまたはFalseを設定します。

Dropbox API

Dropbox.com

Dropboxは、とても有名なストレージサービスです。ファイルをストレージするだけでなく、クラウド上に保存し全てのマシーンと同期してくれます。グループを作ったり、ユーザ個別やグループへ様々なフォルダに対し読み書きの権限を与えることが許可されています。全ファイルのバージョン履歴も保持してくれます。"Public"というフォルダを含んでおり、このフォルダ内のファイルには公開URLが付けられます。共同作業にDropboxは打って付けです。

Dropboxに簡単にアクセスできるようにするには

https://www.dropbox.com/developers

で登録を済まし、APP_KEYAPP_SECRETを取得します。一度それらを取得すると、ユーザのDropboxの認証を使用できます。

"yourapp/private/dropbox.key"ファイルを作り、この様に書きます。

<APP_KEY>:<APP_SECERT>:app_folder

<APP_KEY>APP_SECRETは、それぞれkeyとsecretです。

その次に、"models/db.py"へ次のコードを書きます:

from gluon.contrib.login_methods.dropbox_account import use_dropbox
use_janrain(auth,filename='private/dropbox.key')
mydropbox = auth.settings.login_form

このコードは、ユーザにDropbox認証を扱うアプリへのログインを許可し、あなたのプログラムはユーザのDropboxアカウントにファイルをアップロードすることができます:

stream = open('localfile.txt','rb')
mydropbox.put('destfile.txt',stream)

ファイルのダウンロード:

stream = mydropbox.get('destfile.txt')
open('localfile.txt','wb').write(read)

ディレクトリのリストを取得:

contents = mydropbox.dir(path = '/')['contents']

Twitter API

ツイートを送信/取得する方法の手軽な例を示します。TwitterはシンプルなRESTful APIを利用するため、サードパーティのライブラリを必要としません。

ツイートを送信する方法の例を示します:

def post_tweet(username,password,message):
    import urllib, urllib2, base64
    import gluon.contrib.simplejson as sj
    args= urllib.urlencode([('status',message)])
    headers={}
    headers['Authorization'] = 'Basic '+base64.b64encode(
        username+':'+password)
    req = urllib2.Request(
        'http://twitter.com/statuses/update.json',
        args, headers)
    return  sj.loads(urllib2.urlopen(req).read())

ツイートを受信する方法の例です:

def get_tweets():
    user='web2py'
    import urllib
    import gluon.contrib.simplejson as sj
    page = urllib.urlopen('http://twitter.com/%s?format=json' % user).read()
    tweets=XML(sj.loads(page)['#timeline'])
    return dict(tweets=tweets)

より多くの複雑な操作には、Twitter APIドキュメントを参照してください。

仮想ファイルのストリーミング

streaming

悪意ある攻撃者にとってwebサイトが脆弱かどうかをスキャンするのはよくあることです。彼らはNessusといったセキュリティスキャナを使いスクリプトに脆弱性があるかを知ることで標的となるウェブサイトを探索します。スキャンされたマシンからのwebサーバログや既知の脆弱性の多く示すNessusデータベースでの直接の解析はPHPスクリプトやASPスクリプトにおけるものです。我々はweb2pyを稼動させて以降も、それらの脆弱性が無いにもかかわらず、彼らから未だにスキャンされます。迷惑なので、これらの脆弱性に対応し、攻撃者に彼らの時間を空費することを理解させるのが望ましいです。

1つの方法は攻撃に対抗して.php、.asp、疑わしいダミーアクションへの全リクエストをリダイレクトすることで、攻撃者を長時間忙しくさせ続けることです。そのうち攻撃者はあきらめ、私たちをを二度とスキャンしないでしょう。

このレシピは2つの部品を必要とします。

次のように"default.py"コントローラにjammerという専用のアプリケーションを作成します:

class Jammer():
   def read(self,n): return 'x'*n
def jam(): return response.stream(Jammer(),40000)

このアクションが呼ばれたときに、一度に40000文字の"x"で満たされた無限のデータストリームを返します。

2つ目の要素は.php、.aps(大文字、小文字)などで終わるどのようなリクエストもこのコントローラにリダイレクトする"route.py"ファイルです。

route_in=(
 ('.*.(php|PHP|asp|ASP|jsp|JSP)','jammer/default/jam'),
)

一度目に攻撃を受けた際には小さなオーバヘッドしかないかもしれませんが、私たちの経験からして同じ攻撃者は2度と攻撃してきません。

第3版 - 翻訳: Yota Ichino レビュー: Omi Chiba
第4版 - 翻訳: Yota Ichino レビュー: Omi Chiba
第5版 - 翻訳: Yota Ichino レビュー: Omi Chiba
 top