[Python] print の出力を文字列で取得する

デバッグの時なんかに print の出力内容を、そのまま文字列として取得したかったので方法を調べました。

環境

  • Python 3.4.2

コード

import io
import sys

f = io.StringIO('')
sys.stdout = f
print('-----------------')

s = 'string'
print('文字列', s)

l = ['listVar1', 'listVar2', 'listVar3']
print('リスト', l)

d = {'key1': 'dictVar1', 'key2': 'dictVar2'}
print('辞書', d)

print('モジュール', io)

print('オブジェクト', f)

print('-----------------')

sys.stdout = sys.__stdout__
print('=====================')
f.seek(0)
print(f.read())
print('=====================')
f.close()

出力例

=====================
-----------------
文字列 string
リスト ['listVar1', 'listVar2', 'listVar3']
辞書 {'key1': 'dictVar1', 'key2': 'dictVar2'}
モジュール <module 'io' from 'C:\\Python34\\lib\\io.py'>
オブジェクト <_io.StringIO object at 0x01F18B20>
-----------------

=====================

参考

[nginx] アクセスログにホスト名を追加する

logwatch でホスト名も見たいなと思い nginx のアクセスログにホスト名を追加したのでメモです。

環境

  • nginx/1.6.2

コード

log_format  main  '$remote_addr - $remote_user [$time_local] '
                  '"$request_method $http_host$request_uri $server_protocol" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

デフォルトであった$requestの部分を、ホスト名を追加して$requestの内容を個別にくっつけた形に置き換えています。

参考

[Python][MySQL] row_count() で changed ではなく matched の値を取得する

update など実行するとRows matched: 1 Changed: 0 Warnings: 0のような結果になることがありますが、 通常はrow_count()を実行してもChanged0が返ってくるので、 matched1を返してくれるようにする方法です。 方法としては単純で、接続時にCLIENT_FOUND_ROWSフラグを設定します。

環境

  • MySQL 5.6.15
  • Python 3.4.2
  • MySQL Connector/Python 2.0.2

コード

サンプルコードです。SQL はテキトーで、最初の方はサンプルで使うテーブルを作ってるだけです。

import mysql.connector

options = {
	'host': '127.0.0.1',
	'user': 'root',
	'password': 'pass',
	'database': 'dbname',
	'charset': 'utf8',
}
connect = mysql.connector.connect(**options)
cursor = connect.cursor(dictionary=True)
result = cursor.execute('''
drop table if exists users;
create table users(
	id int primary key,
	name varchar(255)
);
insert into users(id, name) values(1, 'admin'), (2, 'testuser'), (3, 'mysql');
commit;
''', multi=True)
for d in result:
	print(d)

connect.start_transaction()
cursor.execute("update users set name = 'administrator' where id = %(id)s", {'id': 1})
# cursor.execute("select row_count() as row")
# print(cursor.fetchone()['row'])  # 1
print(cursor.rowcount)  # 1

cursor.execute("update users set name = 'administrator' where id = %(id)s", {'id': 1})
# cursor.execute("select row_count() as row")
# print(cursor.fetchone()['row'])  # 0
print(cursor.rowcount)  # 0, 変更された行数
connect.rollback()

# mysql.connector.ClientFlag.FOUND_ROWS を設定する
connect.set_client_flags([mysql.connector.ClientFlag.FOUND_ROWS])
# 途中で設定した場合は reconnect しないと反映されない
connect.reconnect()

connect.start_transaction()
cursor.execute("update users set name = 'administrator' where id = %(id)s", {'id': 1})
print(cursor.rowcount)  # 1

cursor.execute("update users set name = 'administrator' where id = %(id)s", {'id': 1})
print(cursor.rowcount)  # 1, 条件に一致した行数
connect.commit()

cursor.close()
connect.close()

set_client_flagsを使ってmysql.connector.ClientFlag.FOUND_ROWSを指定します。 リストで渡さないとエラーになります。

options = {
	'host': '127.0.0.1',
	'user': 'root',
	'password': 'mik1225',
	'database': 'samples',
	'charset': 'utf8',
	'client_flags': [mysql.connector.ClientFlag.FOUND_ROWS],
}
connect = mysql.connector.connect(**options)

最初の接続時に指定する場合はclient_flagsという名前で指定します。

参考

格安レンタルサーバの 88 SERVER を使ってみた

月額 88 円から利用可能なレンタルサーバの 88 SERVER というサービスを使ってみました。 全然情報がないので不安でしたが、安いということとで人柱的な感じで借りてみました。

プラン

  88 SERVER 288 SERVER
利用料金 1年契約 初期費用 1,000円, 月額 88 円
3年契約 初期費用無料, 月額 88 円
1年契約 初期費用 1,000円, 月額 288 円
3年契約 初期費用無料, 月額 288 円
容量 8GB 28GB
マルチドメイン - 5個
データベース 無制限 無制限
アダルト

88 SERVER プランのドメインは、申込時に入力する一つのみで、ドメインは他サービスで取得しておく必要があるようです。また、最低利用期間は 1 年で、1 年未満で解約しても差額の返金はないようです。

契約

申し込み

申し込みフォームから、契約内容、個人情報、ドメインを入力して送信します。 申込受付の自動返信メールが来ますが、しばらくすると別途請求メールが来るはずです。 私の場合は 10 分以内にメールが来たので、結構対応が早いですね。 ただ、3 年契約にしたはずが、1 年契約の内容で請求メールが来たので、指摘からの再送待ちで追加で 10 分程度時間がかかりました。

支払い

支払いは銀行振込みのみで、支払い後の報告は特に必要ないようです。

サーバ設定

サーバ情報

サーバ情報は振込が確認されてからメールで送られてきます。 今回は、夜のうちに銀行に振込予約、次の日朝一で振込が実行され、サーバ情報のメールが来たのは振込実行日の 21 時少し前でした。 ですので、振込確認からサーバ設定などを行われてメールが来るまで 1 営業日程度はかかるみたいですね。

そしてサーバ情報ですが、パスワード付き zip で圧縮された xlsx ファイルが送られてきました。 ファイルを添付したメールと、パスワードを記載したメールの 2 通です。 解凍して開くと下記情報が記載されていました。

  • FTP 情報
  • メール情報
  • DB ( MySQL ) 情報

それぞれ、アカウントの ID やパスワードなどが記載されています。 また、MySQL データベースは一つ作成された状態で、そのデータベース名とユーザー名、パスワードがありました。

FTP

FTP は平文 FTP でしか接続できませんでした。 FTPS に対応して欲しいですね。

メールアカウント

メールアカウントの管理は、Postfix Admin を使って行えるようです。

データベース

MySQL は phpMyAdmin で管理できるようです。 ただ、新しくデータベース作りたい場合でも、新規作成の権限はもちろんないので、個別に問い合わせして作ってもらう感じみたいですね。 PostgreSQL は問い合わせてないので不明です。

ドメイン

私はサブドメインで申し込んだので、IP を設定するよう記載されていました。 途中でドメインの変更を行いたい場合などは問い合わせる形のようです。

管理画面

契約や、サーバ情報を見たりする画面はないようです。 メールは失くさないようにしないとですね。

レスポンス速度

WordPress をインストールしてみましたが、結構速いです。 体感ではありますが、他のサイト ( WordPress ) で使用している同じ格安系の「ミニバード」よりも速い感じです。

感想

価格の割には十分な機能と速度だと思います。 色々問い合わせが基本になって少し面倒ではありますが、その分変な業者などが来ないんじゃないかと思うので、そう考えると結構いいんじゃないかと思います。

リンク

2014-07-04 追記

外部の監視サービスなので詳細は不明ですが、10 分弱程繋がらない状態になったようです。
07/03 22:46 頃から 5 ~ 10 分
07/04 00:30 頃から 1 ~ 5 分
いまさらですが、サービスサイトにはお知らせとかないから障害が起きてもお知らせはしないつもりなのかもしれないですね。信頼という点ではあまり期待はしないほうがいいかもしれません。

2014-10-10 追記

WordPress 置いていましたが、繋がらないことも多々、ページを開くのに数十秒かかることもあり、まともに使えない状態です。人柱的なことで使ったので大したサイトは置いてませんでしたが、ひどいですね。このサーバは使わないようが良いでしょう。

[PHP] API を使った Google Anapytics のデータ取得と、Google Drive へのファイルアップロードサンプル 2014-05 版

久しぶりに Google API の PHP ライブラリを見ると、Github に移動していてクラス名なども変わっていました。 で、当ブログの「[PHP] Google Analytics API v3.0 を使って解析データを取得する」や [PHP] Google Drive API を使って Google Drive のファイル一覧取得、ファイルの追加を行う などの記事のプログラムが古くなり、そのまま使えない状態でしたので、新しいライブラリに対応したプログラムを書きました。 ただ、そこまで大きく変更されているわけではないようで大きな変更はないです。

環境

  • Google APIs Client Library for PHP 1.0.5-beta

準備

ライブラリはgoogle/google-api-php-clientにあるのでダウンロード等して使用します。 公式ドキュメントには Composer を使ったやり方も書いてあるので、Composer 使ってる人は参照下さい。
Installation - Google APIs Client Library for PHP — Google Developers

また、API を使う際は Google Developers Console で、 使用したい API を有効にして、ID などを取得しておきます。こちらも以前とは画面が変わっていますが、基本は一緒なので説明は省略します。

Google Analytics のサンプル

<?php
// ライブラリのパスを通しておく
// パスは任意に
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).'/google-api-php-client/src');

// ライブラリ読み込み
require('./google-api-php-client/src/Google/Client.php');
// Google Analytics
require('./google-api-php-client/src/Google/Service/Analytics.php');

// セッションスタート
session_start();

$client = new Google_Client();

// クライアントID
$client->setClientId('ここにClient IDを入力');
// クライアントSecret
$client->setClientSecret('ここにClient secretを入力');
// リダイレクトURL
$client->setRedirectUri('ここにRedirect URIsを入力');

$service = new Google_Service_Analytics($client);

// 許可されてリダイレクトされると URL に code が付加されている
// code があったら受け取って、認証する
if (isset($_GET['code'])) {
	// 認証(トークン、リフレッシュトークンを取得)
	$client->authenticate($_GET['code']);
	// 取得したトークンをセッションにセット
	$_SESSION['token'] = $client->getAccessToken();
	// リダイレクト(ここらへんは任意に)
	header('Location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
	die;
}

if (isset($_SESSION['token'])) {
	// トークンセット
	$client->setAccessToken($_SESSION['token']);
}

// トークンがセットされていたら
if ($client->getAccessToken() !== '[]') {

	try {
		 // ビュー ID
		$ids = 'ga:0000000';
		// 期間(スタート)
		$start_date = '2014-05-01';
		// 期間(エンド)
		$end_date = 'today';
		// メトリクス,複数の場合は , で区切る
		$metrics = 'ga:sessions,ga:pageviews';
		// ディメンション,複数の場合は , で区切る
		$dimensions = 'ga:pageTitle,ga:pagePath';
		// ソートする項目, - をつけると降順になります
		$sort = '-ga:pageviews';
		// 最大取得数
		$max_results = 20;
		$optParams = array('dimensions' => $dimensions, 'sort' => $sort, 'max-results' => $max_results);
		$data = $service->data_ga->get($ids, $start_date, $end_date, $metrics, $optParams);

		echo '<pre>';
		var_dump($data);
		echo '</pre>';
	} catch (Google_Exception $e) {
		echo $e->getMessage();
	}

} else {
	// 許可がほしい権限を指定、今回は Google Analytics 全般の操作
	$client->setScopes(Google_Service_Analytics::ANALYTICS);
	// 認証用URL取得
	$authUrl = $client->createAuthUrl();
	echo '<a href="'.$authUrl.'">アプリケーションのアクセスを許可してください。</a>';
}

基本は変わっていないようです。認証の所以外はクラス名を変えるだけで大丈夫でした。

Google Drive のサンプル

ファイルリストを取得する

<?php

// ライブラリのパスを通しておく
// パスは任意に
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).'/google-api-php-client/src');

// ライブラリ読み込み
require('./google-api-php-client/src/Google/Client.php');
// Google Drive
require('./google-api-php-client/src/Google/Service/Drive.php');

// セッションスタート
session_start();

// unset($_SESSION['token']);

$client = new Google_Client();

// クライアントID
$client->setClientId('ここにClient IDを入力');
// クライアントSecret
$client->setClientSecret('ここにClient secretを入力');
// リダイレクトURL
$client->setRedirectUri('ここにRedirect URIsを入力');

$service = new Google_Service_Drive($client);

// 許可されてリダイレクトされると URL に code が付加されている
// code があったら受け取って、認証する
if (isset($_GET['code'])) {
	// 認証(トークン、リフレッシュトークンを取得)
	$client->authenticate($_GET['code']);
	// 取得したトークンをセッションにセット
	$_SESSION['token'] = $client->getAccessToken();
	// リダイレクト(ここらへんは任意に)
	header('Location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
	die;
}

if (isset($_SESSION['token'])) {
	// トークンセット
	$client->setAccessToken($_SESSION['token']);
}

// トークンがセットされていたら
if ($client->getAccessToken() !== '[]') {

	try {

		// 親ディレクトリ
		// root でマイドライブ, root 以外は名前ではなく ID を指定
		$parents = 'root';
		if (isset($_GET['parents'])) {
			$parents = htmlspecialchars($_GET['parents'], ENT_QUOTES);
		}
		// 次ページに移動する場合に渡すトークン
		$pageToken = null;
		if (isset($_GET['pageToken'])) {
			$pageToken = $_GET['pageToken'];
		}
		$parameters = array('q' => "'{$parents}' in parents", 'maxResults' => 20);
		if ($pageToken) {
			$parameters['pageToken'] =$pageToken;
		}
		// ファイルリスト取得, Google_Service_Drive_FileList のオブジェクトが返ってくる
		$files = $service->files->listFiles($parameters);
		// ファイルの一覧データ
		$results = $files->getItems();
		// 次ページのトークン取得, ない場合は NULL
		$pageToken = $files->getNextPageToken();
		// 結果表示
		foreach ($results as $result) {
			// フォルダだったらリンクに
			if ($result->mimeType === 'application/vnd.google-apps.folder') {
				echo '<a href="http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?parents='.urlencode($result->id).'">フォルダ : '.$result->title.'</a><br />';
			} else {
				echo "ファイル : {$result->title}<br />";
			}
		}
		// pageToken があったら次ページヘのリンク表示
		if ($pageToken) {
			echo '<a href="http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?parents='.urlencode($parents).'&pageToken='.urlencode($pageToken).'">次ページ</a>';
		}
	} catch (Google_Exception $e) {
		echo $e->getMessage();
	}

} else {
	// 許可がほしい権限を指定、今回は Google Drive 全般の操作
	// 各クラスで定義されているので、URL を自分で指定するより定義されているものを使ったほうがよいかと
	$client->setScopes(Google_Service_Drive::DRIVE);
	// 認証用URL取得
	$authUrl = $client->createAuthUrl();
	echo '<a href="'.$authUrl.'">アプリケーションのアクセスを許可してください。</a>';
}

ファイルアップロード ( リジューム )

$filename = './test.zip';

// アップロードするファイル情報をセット
$file = new Google_Service_Drive_DriveFile();
$file->setTitle($filename);
$file->setDescription('テストのファイルですよ');
$file->setMimeType('application/zip');

// アップロードする親フォルダを指定
$parent = new Google_Service_Drive_ParentReference();
$parent->setId('0B5abC7E925odY2swdk5CVGdlM0U');
$file->setParents(array($parent));

$client->setDefer(true);
$request = $service->files->insert($file);

// チャンクサイズ, 今回は 256 KB
$chunkSizeBytes = 256 * 1024;
$media = new Google_Http_MediaFileUpload($client, $request, 'application/zip', null, true, $chunkSizeBytes);
$media->setFileSize(filesize($filename));

$status = false;
$handle = fopen($filename, "rb");
while (!$status && !feof($handle)) {
	$chunk = fread($handle, $chunkSizeBytes);
	$status = $media->nextChunk($chunk);
}
fclose($handle);
$client->setDefer(false);

こちらも基本は変わってないですね。

2014-05-05 追記

デフォルトではリフレッシュトークンを取得しないようになっていますね。
リフレッシュトークンも取得したい場合は、access_typeofflineapproval_promptforceをセットする必要があります。

$client->setAccessType('offline');
$client->setApprovalPrompt('force');

参考

1 / 2712345...1020...最後 »