Cloud Translation API Version3(v3beta1)をPHPから。

Google Translation APIを使おうと

翻訳といえば最近だとGoogle翻訳、Google翻訳な私です。
昔はエキサイト翻訳だったりGoo翻訳だったり・・・だった記憶がありますが
それももはや遠い記憶です。
Googleさんの場合ここらへんのAPIがたくさんあるし、MLやAIで精度を高めたりしてくれているので

こりゃいいや

で早速、PHPのライブラリをば頂きに参ったのです。

が・・・

https://cloud.google.com/translate/docs/quickstart-client-libraries-v3?hl=ja

・・・・・・・・・

・・・・・・・・・

・・・・

・・

え・・・

PHPどこ?

ベータ版だからないのだろうか?

もしかしてベータ版だから今一番HOTな言語でしかライブラリがないのだろうか?
そうだとすると待っておくと言う手もあります。
そもそもベータ版ですから仕様はちょこちょこと変更されてしまうので。
でも使ってみたいですよね

なのでREST APIを叩けるように実装しました。

第一の関門 POSTやGETを投げる。


PHPには非常に便利な関数が存在しております。
いや・・・cURL使えって話でしょうけど便利だからついつい使っちゃいます。
API叩くなら特にcURLにしなさいよと言われるんですがそれでも私は・・・

file_get_contentsを愛してやみません。
ローカルのファイルはもちろんまさか・・・URL越しのデータを取得したり、
POSTやらまでできてしまう万能感を愛してやみません。
もちろん気に食わない方はその部分をcURLにすることもよろしいかと。

ちなみにGoogleCloudPlatformにて

「Cloud Translation API」を有効にして、認証情報で「サービスアカウントキーのJSON」バージョンは先に作っておきましょう。

では早速作ってみましょう。

class HttpClient {
protected $_url;
function __construct($url = null) {
$this->_url = $url;
}
public function get($data = array(), $head = array()) {

if ($data) {
$getd = http_build_query($data, "". "&");
}
if ($head) {
$sendHeader = $head;
}
else {
$sendHeader = array(
            'Cache-Control: no-store',
"Content-Type: application/x-www-form-urlencoded",
);
}


$context = array(
"http" => array(
"protocol_version" => "1.1",
"method" => "GET",
"header" => implode("\r\n", $sendHeader),
"ignore_errors" => true
)
);

if ($getd) {
$response = file_get_contents($this->_url . "?{$getd}", false, stream_context_create($context));
}
else {
$response = file_get_contents($this->_url, false, stream_context_create($context));
}
$pos = strpos($http_response_header[0], '200');
if ($pos === false) {
return array(
'status' => 'error',
'error' => $http_response_header[0],
'responce_header' => implode("\n", $http_response_header),
'body' => $response,
);
}
else {
return array(
'status' => 'success',
'body' => $response
);
}
}

public function post($data, $head = array() , $modeJson = false) {
$postd = http_build_query($data, "", "&");
if ($head) {
$sendHeader = $head;
if ($modeJson) {
$postd = $data;
}
else {
$sendHeader[] = "Content-Length: " . strlen($posted);
}
}
else {
$sendHeader = array(
            'Cache-Control: no-store',
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: " . strlen($postd),
);
}
$context = array(
"http" => array(
"protocol_version" => "1.1",
"method" => "POST",
"header" => implode("\r\n", $sendHeader),
"content" => $postd,
"ignore_errors" => true
)
);
$response = file_get_contents($this->_url, false, stream_context_create($context));
$pos = strpos($http_response_header[0], '200');
if ($pos === false) {
return array(
'status' => 'error',
'error' => $http_response_header[0],
'responce_header' => implode("\n", $http_response_header),
'body' => $response,
);
}
else {
return array(
'status' => 'success',
'body' => $response
);
}

}
}

と言うことでHTTPでGETとPOSTするのができました。

JWT(JsonWebToken)を使おう。

OAuth2ではJWTと使ってTokenを取得することにします。
ということでネットのソースやら何やらを色々参考にしながら必要最低限、
JWTを作れるものを

class JWT {
public $_support =  array(
"HS256" => array("hash_hmac", "sha256"),
"HS512" => array("hash_hmac", "sha512"),
"HS384" => array("hash_hmac", "sha384"),
"RS256" => array("openssl", "sha256"),
"RS384" => array("openssl", "sha384"),
"RS512" => array("openssl", "sha512"),
);
protected $_key;

function __construct($key) {
$this->_key = $key;
}
public function encode($body, $header = array("typ" => "JWT", "alg" => "RS256")) {
$iat = time();
$exp = $iat + 3600;

$head = $this->urlsafeB64Encode(json_encode($header));
$body['iat'] = $iat;
$body['exp'] = $exp;
$payload = $this->urlsafeB64Encode(json_encode($body));
$signing = $this->sign($head . "." . $payload);
return $head . "." . $payload . "." . $this->urlsafeB64Encode($signing);
}
protected function sign($msg, $alg = 'RS256') {
if (empty($this->_support[$alg])) {
throw new Exception("error no JWT algorithm");
}
list($func, $algorithm) = $this->_support[$alg];
if ($func == "hash_hmac") {
return hash_hmac($algorithm, $msg, $this->_key, true);
}
else if ($func == "openssl") {
$s = '';
$success = openssl_sign($msg, $s, $this->_key, $algorithm);
if ($success) {
return $s;
}
else {
throw new Exception("open ssl sign error.");
}
}
}
public function urlsafeB64Decode($input){ 
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
public function urlsafeB64Encode($input) {
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
}
作成しました。
うん・・・Excaptionとかの甘さが際立ってます。
申し訳ない。申し訳ない限りです。

GoogleとのOAuth2


GoogleのAPIを叩くにはこのOAuth2を叩いて認証し、そして
一時的なTokenを発行してもらう必要があります。
受け取ったTokenをHeadの要素に付けることでAPIは叩けるようになります。
もちろん最初に発行したサービスアカウントに適切な権限が必要にないりますのでその点はご注意を
さて・・・では・・・

class GoogleOAuth2 {
protected $_scope;
protected $_json;
protected $_token;
protected $_grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";

function __construct($scope, $jsonKey) {
$this->_scope = $scope;
$this->_json = json_decode($jsonKey, true);
}
public function token() {
$jwt = new JWT($this->_json['private_key']);
$jwtData = $jwt->encode(array("iss" =>  $this->_json['client_email'],"aud" => $this->_json['token_uri'],"scope" => $this->_scope));
$client = new HttpClient($this->_json['token_uri']);
$body = $client->post(array('grant_type' => $this->_grantType,'assertion' =>$jwtData));
error_log(var_export($body, true));
if (empty($body['body'])) {
throw Exception("not token");
}
return json_decode($body['body'], true);
}
}

JWT形式のデータを送って、認証を確立し、Tokenをもらいます。

翻訳しようじゃないか

早速翻訳です。
まぁ色々なやり方があるのですが一番シンプルに。

class GoogleTranslate {
const SCOPE = "https://www.googleapis.com/auth/cloud-translation";
const BASEURL = "https://translation.googleapis.com/v3beta1/projects/";
protected $_sourceJson;
protected $_json;
protected $_source;
protected $_target;
function __construct($json, $source = "ja", $target = "en") {
$this->_sourceJson = $json;
$this->_json = json_decode($json, true);
$this->_source = $source;
$this->_target = $target;
}
public function translation($text) {
$google = new GoogleOAuth2(self::SCOPE, $this->_sourceJson);
$token = $google->token();
$url = self::BASEURL . $this->_json['project_id'] . ":translateText";
$xiclient = new HttpClient($url);
$httpHeader[] = "Authorization: Bearer " . $token['access_token'];
$httpHeader[] = "Content-type: application/json; charset=utf-8";

$request = array(
"sourceLanguageCode" => $this->_source,
"targetLanguageCode" => $this->_target,
"contents" => $text
);
$reqjson = json_encode($request);
$translate = $xiclient->post($reqjson, $httpHeader, true);
$translateArr = json_decode($translate['body'], true);
return $translateArr;
}
}

こうしました。

これを一枚のPHPのなかに押し込んでます。
それがいいか悪いかはまぁ・・・別として・・・

使ってみよう。

では使ってみましょう。

まずはGCPから取得しておいたサービアカウントの「JSON」ファイルを読みます。

このときもfile_get_contentsで取得してしまいましょう。
PHPで一番楽だな・・・と思うのはこの関数のおかげです・・・はい。

で使うときはこうです。

$file = "XXXXXXX.json"; ← GCPで取得した「サービスアカウントキー」のJSON
$json = file_get_contents($file);
$googleTranslate = new GoogleTranslate($json);
$text = array(
'こんにちは',
'オッス!オラ悟空!',
'オラ腹減ったぞ!'
);
$d = $googleTranslate->translation($text);

結果は以下になりました。

array(1) {
["translations"]=>
array(3) {
[0]=>
array(1) {
["translatedText"]=>
string(5) "Hello"
}
[1]=>
array(1) {
["translatedText"]=>
string(14) "Oss! Ora Goku!"
}
[2]=>
array(1) {
["translatedText"]=>
string(15) "I'm hungry!"
}
}
}

あくまでサンプルでございますがとりあえず
翻訳はできます。


エラー処理やらなにやらは、是非ご利用頂く方々で実装をよろしくお願いいたします・・・
ライブラリがはやく提供されますように。

2019-10-31 17:21:03

Writer:ゆたさん@開発者。

HomePagehome Twitter Facebook
「Cloud Translation API Version3(v3beta1)をPHPから。」をシェアしませんか?

最新ページ

  • またMVCを作り始めたお話し

    今回はプライベートではなくてオープンなリポジトリとしてGitHubでリポジトリ管理しています。OreOreMVCNagare(つまりここの)MVCの置き換えもし...
  • Steamのゲームでコントローラが効かなくなった時の対応

    環境M1 MacbookAirSteamPS5のコントローラをBluetoothで接続ゲームは、Vampire Survivorsです。現象Steamのコントロ...
  • 作る予定なもの各種。

    お世話になっております。お久しぶりです。Nagareについての記事でございます・・・Nagareのエンジニアのくせに全然、Nagareに関しまして最近発信してい...
  • メタメタメタメタメタバース

    最近やたらとメタバースメタバースと言う言葉が飛び交っております。やはりこのビッグウェーブには乗るしかないのでしょうか。問題はどう言う方法でこの「メタバース」の波...
  • 着手するまでが時間がかかると言うおはなし

    何かを始めようとするときに計画まではOKで実際に実行する時時間がかかりませんか?腰が重い・・・身体がダル重い感じが・・・こう・・・やる気がどこかに言ってしまって...