質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

4回答

3490閲覧

PHPのAPIを作る勉強中ですが

lol

総合スコア85

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

2クリップ

投稿2016/03/25 06:52

phpでapiを作る勉強中です。

http://localhost/test/apiTest.php?id=1234
http://localhost/test/apiTest.php?flg=1
というURLで、
apiTest.phpにidを渡して、処理する部分はできました。

idから名前を取得する部分と

仮にflgというパラメータが来るとして、
このflgで別のロジックを処理したい場合は、
ファイルを分ける方法しかございませんか??

今私のレベルでは、ファイル分けて処理するしか思い浮かばずです。

メソッドを分けて呼べる方法とかはありませんか??

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HiroshiWatanabe

2016/03/25 07:09

(理解できていないのが私だけなら申し訳ないんですけども) ファイルを分けるという意味がよくわからないんですが apiTest.php?flg=1ができないからapiTest2.php?flg=1 としなくてはならない、という事…でも無いですよね? 質問の意図がよく理解できません… 「こういう処理を期待してこう記述したけどこんなエラーが出てしまう」 みたいな情報があればしたいことと困ってる内容がわかって答えやすいかも…
lol

2016/03/25 07:14

質問が悪かったです。すみません。 まず、ファイルを分けるという意味は パラメータが異なる場合の事を伝えるつもりでした。 1.http://localhost/test/apiTest.php?id=1234 パラメータがIDが来る場合 2.http://localhost/test/apiTest.php?flg=1 パラメータがflgが来る場合 この場合に同じファイルでは、別々の処理ができないような気がしました。 また、 3.http://localhost/test/apiTest.php?id=1234&name=suzuki これもあったとしたら、区別をつけないといけないかなと思って質問しました。 パラメータは5個とか来ると処理できないよなぁと一人で悩んでました。
guest

回答4

0

ベストアンサー

**「1ファイルに1処理」**というスタイルは,HTML+CSSしか書けなかった素人がWebプログラミングに手をだすための敷居こそ低いものの,機能が増えてくると設計が破綻してきます.「register.php」「postMessage.php」「showMessage.php」「editMessage.php」「showUser.php」「editUser.php」みたいなファイルが大量に並べられることでしょう.

これを防ぐためにPHPを用いた中規模以上の開発ではMVCフレームワークを用いた開発を行うのが一般的です.いきなりこれが敷居が高く感じられるのであれば,V以外を極限まで小さく抑えるマイクロフレームワークを使っても構いません.(後々MVCのほうが良かった,と思うことは多いですが,入門用としてマイクロフレームワークは悪い選択肢ではありません)

「1ファイルに1処理」問題を解決するためにあるのがルーティングです.これはMVCフレームワークでもマイクロフレームワークでも使われます.ルーティングはURLを見てどういう処理を実行するのかを制御するものです.「*.php」の拡張子を消すことが出来たり,必ずしもパラメータを「?a=b&c=d」の形式で渡す必要がないのもメリットです.例えばこんな感じ.

  • 「/entry/list」にGETでアクセスが来たら,投稿一覧を取得する
  • 「/entry/post」にPOSTでアクセスが来たら,新規投稿を追加する
  • 「/user/profile/ユーザ名」にGETでアクセスが来たら,該当ユーザのプロフィールを取得する

この「〜を取得する」の処理の部分ですが,これを1ファイルにまとめる必要はありません.堂々と分離させましょう.この際,処理をクラスメソッドや関数として定義しておくと,全体の見通しがよくなります.グローバルスコープに処理をズラズラ書き並べるのは可能な限り避けましょう

上記の「コールバックには何が使えるか?」のところでいろいろなパターンが紹介されています.Slimの公式ドキュメントではクロージャを使ったものがほとんどですが,これを乱立させてしまうとまた1ファイルが膨大になってくるのでおすすめできません.**「クラス名:メソッド名」**が一番いいかと思います.

今回はAPIを作りたい,ということでしたよね?おそらくレスポンスをJSONで返すだけだと思うので,ビューに特別な手間をかける必要はないです.以下のように $response オブジェクトから withJSON() メソッドを生やすだけです.

php

1$app->get('/user/profile/{name}', 'UserController:showProfile'); 2 3class UserController 4{ 5 public function showProfile($request, $response, $args) 6 { 7 $params = $request->getQueryParams(); 8 return $response->withJSON([ 9 'name' => $args['name'], 10 'description' => "{$args['name']}のプロフィール", 11 'flag_enabled' => !empty($params['flag']), 12 ]); 13 } 14}

注意: Slim3のwithJsonはステータスコードをデフォルトで200に書き換える

上記のルーティングを行っている場合, http://example.com/user/profile/CertaiN?flag=1 でアクセスすると以下のようなJSONが返ってくるはずです. (見やすくしています)

json

1{ 2 "name": "CertaiN", 3 "description": "CertaiNのプロフィール", 4 "flag_enabled": true 5}

なお実際にはデータベースに繋いでユーザ情報を取得してくることになると思いますが,全てのメソッドの中にPDOを扱う処理を毎回記述するのは非常に冗長なので,こういう処理は別のクラスにまとめておきましょう.そして,Slim\Appのインスタンスを作る際に渡すコンテナにあらかじめ突っ込んでおき,後から参照するようにしましょう.例えばこんな感じ.

(サービスロケータというアンチパターンを使っているんですが,まぁSlim3がそういう設計思想なのでしょうがないですね)

php

1$container = new Slim\Container; 2$container['db'] = function () { return new DB; }; 3 4$app = new Slim\App($container); 5$app->get('/user/profile/{name}', 'UserController:showProfile'); 6 7class UserController 8{ 9 private $db; 10 public function __construct(ContainerInterface $container) 11 { 12 $this->db = $container['db']; 13 } 14 public function showProfile($request, $response, $args) 15 { 16 $params = $request->getQueryParams(); 17 return $response->withJSON([ 18 'name' => $args['name'], 19 'description' => $this->db->getDescriptionByName($args['name']), 20 ]); 21 } 22} 23 24class DB 25{ 26 private $dbh; 27 public function __construct() 28 { 29 $this->dbh = new PDO(...); 30 } 31 public function getDescriptionByName($name) 32 { 33 $stmt= $this->dbh->prepare(...); 34 ... 35 return ...; 36 } 37}

投稿2016/03/25 14:17

編集2016/03/25 14:55
mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lol

2016/03/28 00:42

このような回答がほしかったです。ありがとうございます。 MVCフレームワークを使うとできるとのことですね? また、DBの接続を毎回するのも悩んでました。 まずは、クラス化をして分離してみます。 ありがとうございます。
guest

0

なんだかよくわからないけど、

今私のレベルでは、ファイル分けて処理するしか思い浮かばずです。メソッドを分けて呼べる方法とかはありませんか??

パラメータでメソッドとかを指定すると同じファイルでも分けて処理ができるのかが知りたいことでした。

これですと、idとflgが同時に来るパターンはまた分岐するということでしょうか??

クラス化まではまだなので、さっぱりですが

という良い子のみんなの意見を纏めると、

apiTest.php

PHP

1if(isset($_GET["id")){ 2 doIdMethod($_GET["id"]); 3} 4 5if(isset($_GET["flg"])){ 6 doFlgMethod($_GET["flg"]); 7} 8 9function doIdMethod($id){ 10 // $idでの処理 11} 12 13function doFlgMethod($flg){ 14 // $flgでの処理 15}

こんなんでましたけど?

投稿2016/03/25 11:31

編集2016/03/25 11:35
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lol

2016/03/28 00:42

これは違います。
guest

0

クラス化してみたら幸せになれるかも?

投稿2016/03/25 07:46

HiroshiWatanabe

総合スコア2160

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lol

2016/03/25 07:57

ちなみに、 $dsn = 'mysql:dbname=test;host=localhost'; $user = 'testuser'; $password = 'testuser'; $id = $_GET['id']; try{ $dbh = new PDO($dsn, $user, $password); $dbh->query('SET NAMES sjis'); $sql = 'select id, name from name_table where id == ?'; $stmt = $dbh->prepare($sql); $stmt->execute(array($id)); while($result = $stmt->fetch(PDO::FETCH_ASSOC)){ print($result['id']); print($result['name'].'<br>'); } }catch (PDOException $e){ print('Error:'.$e->getMessage()); die(); } これをクラス化するのは簡単にできるものでしょうか??
HiroshiWatanabe

2016/03/25 08:26

>ここを見る限りでは、クラス化しないといけないようですね。 クラスにしなくても要求を満たす事はできると思います。 答えに至る道(実現手段)は1つではありませんので。 >これをクラス化するのは簡単にできるものでしょうか?? はい。クラスにする事自体はそんなにムズカシイ事ではありません。
guest

0

ん?

PHP

1if (@$_GET['flg'] == 1) { 2 // 1の処理 3} 4elseif ($_GET['flg'] == 2) { 5 // 2の処理 6} 7else { 8 // その他 9}

みたいな?

###追記
パラメータに値を付けると、HTTPプロトコルではGETでデータを受け取ることになります。
フォームなどにデータを入力してデータを受け取る場合、POSTでデータを受け取ります。

しかし、実はリクエストヘッダーの中身を見ると興味深いです。

flg=1&id=1234&name=suzuki ```のように渡しています。 そして、PHPはそのデータを直接利用することができます。 ```PHP $id = $_POST['id']; ```とするだけで、idを変数に入れて利用可能です。 これはURLパラメータでも同じです。

投稿2016/03/25 07:09

編集2016/03/26 03:50
shi_ue

総合スコア4437

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lol

2016/03/25 07:17

これですと、idとflgが同時に来るパターンはまた分岐するということでしょうか??
shi_ue

2016/03/25 07:19

まあ、分岐したければそうすればいいですし、その値を使って他の処理をするなら、そうすればいいです。 ソースをご提示いただけていないので、何とも答えようがありません。
lol

2016/03/25 07:27

$dsn = 'mysql:dbname=test;host=localhost'; $user = 'testuser'; $password = 'testuser'; $id = $_GET['id']; try{ $dbh = new PDO($dsn, $user, $password); $dbh->query('SET NAMES sjis'); $sql = 'select id, name from name_table where id == ?'; $stmt = $dbh->prepare($sql); $stmt->execute(array($id)); while($result = $stmt->fetch(PDO::FETCH_ASSOC)){ print($result['id']); print($result['name'].'<br>'); } }catch (PDOException $e){ print('Error:'.$e->getMessage()); die(); } コードならこれですけど、想定の話でしたので。。 関連のない処理の場合に同じファイルで全部書くのができるのかの質問です。 SQLとか、最終的にはjsonに変換するので、別ファイルわけだと同じ処理を何回もしないといけないような気がして。
shi_ue

2016/03/25 07:38

APIだから、関連がない動作を一つのファイルでやるのはどうか、という質問なんですか? ちょっと質問の意図が読み取れません。ソースを見てもidしかないし・・・
lol

2016/03/25 07:47

http://www.objective-php.net/mvc/dispatcher ここに記載されている、 コントローラーの振り分けみたいのができるのかと思ってました。 $controller = 'index'; if (0 < count($params)) { $controller = $params[0]; } // パラメータより取得したコントローラー名によりクラス振分け $controllerInstance = null; switch ($controller) { case 'index': $controllerInstance = new IndexController(); break; case 'product': $controllerInstance = new ProductController(); break; case 'cart': $controllerInstance = new CartController(); break; default: header("HTTP/1.0 404 Not Found"); exit; break; } パラメータでメソッドとかを指定すると同じファイルでも分けて処理ができるのかが知りたいことでした。
mpyw

2016/03/25 14:22

「リクエストを受け取った段階で問答無用でサニタイズする」というのは誤った設計です.「エスケープすべき瞬間にその用途に応じたエスケープを行う」のが正しいです.詳しくは「サニタイズ言うなキャンペーン」でググってください.このキャンペーン啓発者曰く「サニタイズは死語として扱うべきだ」だそうですが,そのとおりだと思います.
mpyw

2016/03/25 14:30

>> $dbh->query('SET NAMES sjis'); これは絶対にやめてください.この書き方をするとプレースホルダを使っていてもSQLインジェクションを受ける可能性があります.詳しくは以下の徳丸さんのブログを参照してください. http://www.tokumaru.org/d/20100701.html 設計方針としては,まずそもそもShift_JISなんて古臭い文字コードを使わないこと.今のWebでは全ての文字コードをUTF-8に統一するのがもはや当たり前です.Shift_JISをPHPで使うとデメリットが沢山あります.例えば str_replace や explode といった関数はよく使うと思いますが,Shift_JISエンコードされた文字列に対しては動作保証されていません.また,文字コードの設定にはDSNのcharset指定を使うようにしてください. $dsn = 'mysql:dbname=test;host=localhost;charset=utf8'; >> $sql = 'select id, name from name_table where id == ?'; これ構文エラーになると思います.SQLの比較は「==」じゃなくて「=」です. また,SQLの構文エラーなどにもすぐ気づけるように,「new PDO」以外の部分でもPDOExceptionがスローされるように必ず以下の設定を最初に行ってください.これを行わないと全体をtry~catchで括る意味がありません. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
shi_ue

2016/03/26 03:51

Re: CertaiNさん 老婆心で余計な一言を入れてしまいました。言われてみればそうですよね。 わたしもサニタイズなんてしてませんし(笑) 初心者のように見えるからって、いい加減なことを書かないように気を付けます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問