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

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

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

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

Q&A

解決済

1回答

453閲覧

class内でmove_uploaded_file後、そのファイルパスを取得するには

arahito

総合スコア18

PHP

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

0グッド

0クリップ

投稿2019/04/10 10:06

編集2019/04/10 15:59

前提・実現したいこと

https://qiita.com/mpyw/items/73ee77a9535cc65eff1e

発生している問題・エラーメッセージ

おそらくこの部分のどこかにmove_uploaded_fileが使われてファイルが保存されるはずなのですが、!$output(~の部分が何をやっているのか全くわかりません。
また、ハッシュをとってファイル名を名付けた場合、その後どのようにすればファイルパスを取得できるのか全くわかりません。
わからないことばかりで申し訳ないのですが、以下を画像アップロードのバリデーションクラスとして定義して使う場合、保存したファイルのファイルパスをphpファイルで呼び出したい場合、どのように呼び出せば使えるのでしょうか?

// ファイルデータからSHA-1ハッシュを取ってファイル名を決定し、保存する if (!$output( $dst, sprintf('./resized/%s%s', sha1_file($_FILES['upfile']['tmp_name'][$k]), image_type_to_extension($info[2]) ) )) { throw new RuntimeException("[{$k}] ファイル保存時にエラーが発生しました"); } $msgs[] = ['green', "[{$k}] リサイズして保存しました"]; } catch (RuntimeException $e) { $msgs[] = ['red', $e->getMessage()]; }

該当のソースコード

<?php if (isset($_FILES['upfile']['error']) && is_array($_FILES['upfile']['error'])) { // 各ファイルをチェック foreach ($_FILES['upfile']['error'] as $k => $error) { try { // 更に配列がネストしていれば不正とする if (!is_int($error)) { throw new RuntimeException("[{$k}] パラメータが不正です"); } // $_FILES['upfile']['error'][$k] の値を確認 switch ($error) { case UPLOAD_ERR_OK: // OK break; case UPLOAD_ERR_NO_FILE: // ファイル未選択 continue 2; case UPLOAD_ERR_INI_SIZE: // php.ini定義の最大サイズ超過 case UPLOAD_ERR_FORM_SIZE: // フォーム定義の最大サイズ超過 throw new RuntimeException("[{$k}] ファイルサイズが大きすぎます"); default: throw new RuntimeException("[{$k}] その他のエラーが発生しました"); } // $_FILES['upfile']['mime']の値はブラウザ側で偽装可能なので // MIMEタイプを自前でチェックする if (!$info = @getimagesize($_FILES['upfile']['tmp_name'][$k])) { throw new RuntimeException("[{$k}] 有効な画像ファイルを指定してください"); } if (!in_array($info[2], [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG], true)) { throw new RuntimeException("[{$k}] 未対応の画像形式です"); } // 画像処理に使う関数名を決定する $create = str_replace('/', 'createfrom', $info['mime']); $output = str_replace('/', '', $info['mime']); // 縦横比を維持したまま 120 * 120 以下に収まるサイズを求める if ($info[0] >= $info[1]) { $dst_w = 120; $dst_h = ceil(120 * $info[1] / max($info[0], 1)); } else { $dst_w = ceil(120 * $info[0] / max($info[1], 1)); $dst_h = 120; } // 元画像リソースを生成する if (!$src = @$create($_FILES['upfile']['tmp_name'][$k])) { throw new RuntimeException("[{$k}] 画像リソースの生成に失敗しました"); } // リサンプリング先画像リソースを生成する $dst = imagecreatetruecolor($dst_w, $dst_h); // getimagesize関数で得られた情報も利用してリサンプリングを行う imagecopyresampled($dst, $src, 0, 0, 0, 0, $dst_w, $dst_h, $info[0], $info[1]); // ファイルデータからSHA-1ハッシュを取ってファイル名を決定し、保存する if (!$output( $dst, sprintf('./resized/%s%s', sha1_file($_FILES['upfile']['tmp_name'][$k]), image_type_to_extension($info[2]) ) )) { throw new RuntimeException("[{$k}] ファイル保存時にエラーが発生しました"); } $msgs[] = ['green', "[{$k}] リサイズして保存しました"]; } catch (RuntimeException $e) { $msgs[] = ['red', $e->getMessage()]; } // リソースを解放 if (isset($msg) && is_resource($img)) { imagedestroy($img); } if (isset($dst) && is_resource($dst)) { imagedestroy($dst); } } }

試したこと

補足情報(FW/ツールのバージョンなど)

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

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

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

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

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

guest

回答1

0

ベストアンサー

前提として、PHPは関数名などを変数にして呼び出すことが可能です。

php

1<?php 2function hoge(){ 3 echo "hoge"; 4} 5 6$test = "hoge"; 7$test();

それは、ユーザー定義関数であっても標準関数であっても同じです。
その基準で追っていくと

$output という変数名で実行する関数が定義されている

$output$output = str_replace('/', '', $info['mime']);で定義されている

$infoif (!$info = @getimagesize($_FILES['upfile']['tmp_name'][$k])) {で定義されている

getimagesize()で一時ファイルから情報を取得していてMIMEタイプであることが分かる

MIMEタイプを調べると例えばjpg画像であればimage/jpegが設定されることがわかる

ということはstr_replace('/', '', $info['mime']);によってimagejpegとなることが分かる

phpの標準関数imagejpeg() が使われることが分かる

という感じですね。
まあ、変数なのでvar_dump()でもprint_r()でもデバッグすれば何が入っているかは一目瞭然ですが、「なぜその情報が入るか」の追い方の参考にしてください。

あと、ご提示の記事は結構丁寧にコメントが書かれているので、どのような意図で処理が書かれたかはコメントと処理をあわせると理解しやすいと思います。


前提その2.

$_FILEで扱ってるのはサーバー上に送信されたファイル。
そもそもmove_uploaded_file()アップロードされたファイルを新しい位置に移動する機能なので、使う時点でサーバーにテンポラリファイルとしてアップロードがすんでいます。

同じ方が書いた記事にファイルアップロードの例外処理はこれぐらいしないと気が済まないというのがありますが、「move_uploaded_file じゃなくて rename じゃだめ?」という提案がなされていて、記事も一本出来上がっています。

よって、今回の質問提示のコードではmove_uploaded_file()ではなく、別の関数で画像を移動させていることになります。
imageX系の関数は 画像をブラウザあるいはファイルに出力する機能を持ちますので、例に挙げたimagejpeg()であれば画像 image(今回はテンポラリファイル) から JPEG ファイルを作成し、第2引数toの宛先に出力(移動)された、ということになります。


よって

画像アップロードのバリデーションクラスとして定義して使う場合

既に画像アップロードまで行ってしまっていることになりますので、このままバリデーションだけで使うのは難しいのではないでしょか。
どこまでを「バリデーション」とするかによりますが、ファイル生成はバリデーションを行った後のものと考えるのが通常なので、例えば、「ファイルが画像か」「サイズ超過していないか」「指定した画像拡張子か」のチェックまでを切り出してバリデーションとすることになるのではないでしょうか。

あとは画像をきちんと移動できるかどうかなので異常系に分類されると思います。


保存したファイルのファイルパスをphpファイルで呼び出したい場合

「保存した」なので「移動済み」でしょうか、それとも「テンポラリファイル」でしょうか。
それによって違います。移動済みなのであればハッシュしているとはいえシステム側から払い出したファイル名です。如何様にもできますよね。
それに「どこでどう使いたいか」によります。
前述の「バリデーションのため」であればわざわざパスを取り出す必要はあません。$_FILEはスーパーグローバル変数なのでPHPプログラムのどこからでも呼び出せます。

「ファイルが画像か」「サイズ超過していないか」「指定した画像拡張子か」くらいならtmp_nameからチェックできます(すでに記事のコードではそのように対応されてますよね)


提示の記事のコードはそれ1つで全て出来上がっているものなので、
そこから何とか切り出そうとすると整合性を取るのが難しくなると思います。
それなりに技術力と経験と発想、ロジックが必要になります。

まずは参考にとどめ、このコードのまま挙動確認・デバッグを行って身にしていってはどうでしょうか。

投稿2019/04/11 02:20

m.ts10806

総合スコア80850

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

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

arahito

2019/04/11 06:37 編集

丁寧な解説ありがとうございます。 質問するために文章に書き出してみたらその数時間後になんとなくこうだろう、と少し理解できたのですが、 どこからどこへ呼び出すかで変数の書き方が違うと思うのですが、 Common.class.php public function ImageCheck() { ... $path = sprintf(Bootstrap::IMG_FILE_DIR . '%s', sha1_file($_FILES['image']['tmp_name']) . $this->getImageType($info['mime'])); $this->path = $path; ... } giftconfirm.php use gift\lib\Common; $common = new Common(); ... $path = $common->path; ... このようにして呼び出すことはできたのですが、$this->pathに$pathを代入しなおす?ところがいまいち理解できません。 private に設定してあったのですが、publicに変更しました。この記述方法でも、またそれ以外の記述方法だとしてもprivateの場合は外部から呼び出すことはできないのですよね?
m.ts10806

2019/04/11 06:39

>publicの場合は外部から呼び出すことはできないのですよね? publicとstaticは外から呼び出せます。 https://www.php.net/manual/ja/language.oop5.visibility.php ただ、staticはインスタンスからでは呼び出せません。 ところでそのCommon.class.phpはどこから出たものですか? 提示の記事には含まれていません。もう少し検証されてから別質問とされてはどうでしょうか。
arahito

2019/04/11 06:47

>publicの場合は外部から呼び出すことはできないのですよね? 間違えました。privateです。コメント書き直しました。 > https://www.php.net/manual/ja/language.oop5.visibility.php このページめちゃくちゃわかりやすいです。ありがとうございます!
m.ts10806

2019/04/11 06:53

PHPで開発をするのならPHPマニュアルはどんな入門書籍やネットの記事よりも重要です。 いわば仕様書なので。最も正しいことが書いてあります。公式マニュアルです。
arahito

2019/04/11 06:58

公式ドキュメント重要ですよね。 解決したい事柄をまだうまく言語化できなくて、PHPマニュアルの該当ページを参照するにまで至らないんですよね。。 コツコツ頑張ります!
m.ts10806

2019/04/11 07:01

まずは辞書と思って使ったらいいですよ。 しっかり言語化する必要もなくて、文語過ぎない程度に「システムっぽい感じで」なるべくコードを書くように文章化すれば、キーワードも出てきやすいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問