この章では、新しい従業員レコードのJPEGイメージをアップロードして「Employees」ページに表示するためにアプリケーションを変更する方法について説明します。内容は次のとおりです。
この項では、従業員のレコードに写真を格納できるようにアプリケーション・コードを変更します。
従業員レコードに従業員のイメージを格納できるようにするには、次の手順を実行します。
chap7ディレクトリを作成し、chap6からアプリケーション・ファイルをコピーし、新しく作成したディレクトリに移動します。
Windowsの場合:
mkdir c:\program files\Apache Group\Apache2\htdocs\chap7 cd c:\program files\Apache Group\Apache2\htdocs\chap7 copy ..\chap6\* .
Linuxの場合:
mkdir $HOME/public_html/chap7 cd $HOME/public_html/chap7 cp ../chap6/* .
SQL Developerを起動し、HRサンプル・スキーマへの接続をオープンします。
hrユーザーとしてHRサンプル・スキーマにログインします。
SQLワークシートを開き、次のCREATE TABLE文を入力して、従業員イメージを格納するための新しい表を作成します。
CREATE TABLE employee_photos( employee_id NUMBER, employee_thumbnail BLOB);

HRユーザーがこのコマンドを実行するには、CREATE TABLE権限が必要です。「insufficient privileges」エラー・メッセージが戻された場合は、HRユーザーとしてログアウトしてから、systemとしてログインし、次のGRANTコマンドを実行します。
GRANT create table TO hr;
次に、再度HRとしてログインして、CREATE TABLE文を実行します。
anyco_ui.incファイルを編集します。 ui_print_employees()関数のEMPLOYEES表に「Photograph」列を追加します。
<th>Commission<br>(%)</th>
<th>Remuneration</th>
<th>Photograph</th>
「Photograph」列のデータは、<img>タグ付きで移入されます。このタグでは、src属性が新しいanyco_im.phpファイルへのURL参照として定義されているため、従業員レコードごとにイメージが表示されます。
anyco_ui.incファイルを編集します。 ui_print_employees()関数に、従業員IDをパラメータとして指定して、anyco_im.phpファイルを参照する<img>タグを生成するコードを追加します。
echo '<td align="right">'
.htmlentities($emp['REMUNERATION']).'</td>';
echo '<td><img src="anyco_im.php?showempphoto='.$emp['EMPLOYEE_ID']
.'" alt="Employee photo"></td>';
anyco_ui.incファイルを編集します。 新しい従業員レコードの作成時にイメージをアップロードできるようにするには、ui_print_insert_employee()関数の<form>タグにenctype属性を追加します。
<form method="post" action="$posturl" enctype="multipart/form-data">
フォームの下部にアップロード用のフィールドを追加し、その入力タイプをfileに設定します。
<tr> <td>Commission (%)</td> <td><input type="text" name="commpct" value="0" size="20"></td> </tr> <tr> <td>Photo</td> <td><input type="file" name="empphoto"></td> </tr>
anyco_im.php fileファイルを作成します。 このファイルは、URLパラメータとして従業員IDをとり、その従業員レコードの「Photograph」列からイメージを読み取り、表示するサムネイル・イメージを戻します。
<?php // anyco_im.php require('anyco_cn.inc'); require('anyco_db.inc'); construct_image(); function construct_image() { if (!isset($_GET['showempphoto'])) { return; } $empid = $_GET['showempphoto']; $conn = db_connect($err); if (!$conn) { return; } $query = 'SELECT employee_thumbnail FROM employee_photos WHERE employee_id = :eid'; $stid = oci_parse($conn, $query); $r = oci_bind_by_name($stid, ":eid", $empid, -1); if (!$r) { return; } $r = oci_execute($stid, OCI_DEFAULT); if (!$r) { return; } $arr = oci_fetch_row($stid); if (!$arr) { return; // photo not found } $result = $arr[0]->load(); // If any text (or whitespace!) is printed before this header is sent, // the text is not displayed. The image also is not displayed properly. // Comment out the "header" line to see the text and debug. header("Content-type: image/JPEG"); echo $result; } ?>
construct_image()関数は、OCI-Lob->load()関数を使用して、イメージ・データであるOracle LOBデータを取り出します。 PHPのheader()関数は、HTTPレスポンス・ヘッダーにMIMEタイプを設定して、ブラウザがデータをJPEGイメージとして認識できるようにします。
anyco_db.incファイルを編集します。 EMPLOYEE_PHOTOS表にイメージを挿入する新しい関数db_insert_thumbnail()を追加します。
function db_insert_thumbnail($conn, $empid, $imgfile, &$e) { $lob = oci_new_descriptor($conn, OCI_D_LOB); if (!$lob) { $e = db_error($conn, __FILE__, __LINE__); return false; } $insstmt = 'INSERT INTO employee_photos (employee_id, employee_thumbnail) VALUES(:eid, empty_blob()) RETURNING employee_thumbnail into :etn'; $stmt = oci_parse($conn, $insstmt); $r = oci_bind_by_name($stmt, ':etn', $lob, -1, OCI_B_BLOB); if (!$r) { $e = db_error($stid, __FILE__, __LINE__); return false; } $r = oci_bind_by_name($stmt, ':eid', $empid, -1); if (!$r) { $e = db_error($stid, __FILE__, __LINE__); return false; } $r = oci_execute($stmt, OCI_DEFAULT); if (!$r) { $e = db_error($stid, __FILE__, __LINE__); return false; } if (!$lob->savefile($imgfile)) { $e = db_error($stid, __FILE__, __LINE__); return false; } $lob->free(); return true; }
新しいEMPLOYEE_PHOTOS表とEMPLOYEES表を結び付けるには、両方の表で同じ従業員IDを使用する必要があります。
anyco_db.incファイルを編集します。 OUTバインド変数値がデータベースから戻されるように、db_execute_statement()関数の$bindvarsパラメータを&$bindvarsに変更します。 この関数の下部に、戻されたバインド変数値を設定するループを追加します。
function db_execute_statement($conn, $statement, &$e, &$bindvars = array()) { ... $r = @oci_execute($stid); if (!$r) { $e = db_error($stid, __FILE__, __LINE__); return false; } $outbinds = array(); foreach ($bindvars as $b) { $outbinds[$b[0]] = $$b[0]; } $bindvars = $outbinds; return true; }
anyco.phpファイルを編集します。バインド変数:neweidに新しい従業員IDが戻されるように、insert_new_emp()関数のINSERT文を変更します。 この値がイメージとともに新しいEMPLOYEE_PHOTOS表に挿入されます。
$statement =
'INSERT INTO employees
(employee_id, first_name, last_name, email, hire_date,
job_id, salary, commission_pct, department_id)
VALUES (employees_seq.nextval, :fnm, :lnm, :eml, :hdt,
:jid, :sal, :cpt, :did)
RETURNING employee_id into :neweid';
また、insert_new_emp()関数で、array_push()関数へのコールを追加して、新しいバインド変数NEWEIDをarray_push()コールのリストの最後に設定します。
array_push($bindargs, array('CPT', $newemp['commpct'], -1));
array_push($bindargs, array('DID', $newemp['deptid'], -1));
array_push($bindargs, array('NEWEID', null, 10));
NEWIDの値はINSERT文のRETURNING句で取り出されるため、その初期値はNULLに設定します。長さは、戻り値に十分な桁を確保するために10に設定します。
anyco.phpファイルを編集します。insert_new_emp()関数で、db_execute_statement()コールとconstruct_employees()コールの間にサムネイル・イメージを挿入するコールを追加します。
$r = db_execute_statement($conn, $statement, $err, $bindargs);
if ($r) {
$r = db_insert_thumbnail($conn, $bindargs['NEWEID'],
$_FILES['empphoto']['tmp_name'], $e);
construct_employees();
}
Windowsの場合:
http://localhost/chap7/anyco.php
Linuxの場合:
http://localhost/~<username>/chap7/anyco.php
「Departments」ページで、「Show Employees」をクリックして「Employees」ページにナビゲートします。

「Employees」ページで、新しい従業員レコードを挿入するには、「Insert new employee」をクリックします。

「Insert New Employee」フォームでは、データベースにアップロードするシステム上のサムネイル・イメージを選択できます。次の各フィールドに独自の値を入力するか、または表示されている値を使用します。「Browse」をクリックします。

「File Upload」ウィンドウで、JPEGイメージ・ファイルを参照して選択し、「Open」をクリックします。

「Insert New Employee」ページで、「Save」をクリックします。

「Employees」ページに、元のサイズのイメージを含む新しい従業員レコードが表示されます。

この項では、アプリケーション・コードをさらに変更して、指定したイメージからサムネイル・イメージを作成し、従業員のレコードにそのサムネイル・イメージを格納します。
PHPのGDグラフィックス拡張モジュールを使用して、従業員イメージをサイズ変更します。
Apacheを再起動します。ApacheMonitorユーティリティを使用するか、またはWindowsのサービスを使用できます。
ApacheMonitorユーティリティを使用するには、Apacheのbinディレクトリに移動し、ApacheMonitor.exeをダブルクリックします。デフォルトのインストールでは、Apacheのbinディレクトリはc:\Program Files\Apache Group\Apache2\binです。
Windowsのサービスにアクセスするには、Windowsの「スタート」メニューで、「スタート」→「コントロール パネル」→「管理ツール」→「サービス」を選択します。「標準」タブを選択します。「Apache2 HTTP Server」を右クリックし、「再起動」を選択します。
anyco_db.incファイルを編集します。 イメージをサイズ変更してサムネイル・イメージを作成するには、db_insert_thumbnail()関数で$lob->savefile($imgfile)へのコールの前に次のコードを追加します。
$r = oci_execute($stmt, OCI_DEFAULT);
if (!$r) {
$e = db_error($stid, __FILE__, __LINE__);
return false;
}
// Resize the image to a thumbnail
define('MAX_THUMBNAIL_DIMENSION', 100);
$src_img = imagecreatefromjpeg($imgfile);
list($w, $h) = getimagesize($imgfile);
if ($w > MAX_THUMBNAIL_DIMENSION || $h > MAX_THUMBNAIL_DIMENSION)
{
$scale = MAX_THUMBNAIL_DIMENSION / (($h > $w) ? $h : $w);
$nw = $w * $scale;
$nh = $h * $scale;
$dest_img = imagecreatetruecolor($nw, $nh);
imagecopyresampled($dest_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);
imagejpeg($dest_img, $imgfile); // overwrite file with new thumbnail
imagedestroy($src_img);
imagedestroy($dest_img);
}
if (!$lob->savefile($imgfile)) {
...
imagecreatefromjpeg()関数を使用して、JPEGファイルを読み取り、後続のGD関数で使用される内部表現を作成しています。次に、最長側面が100ピクセル以下の新しい次元を計算しています。imagecreatetruecolor()関数を使用して、その新しいサイズのテンプレート・イメージを作成しています。imagecopyresampled()関数を使用して元のイメージのデータをそのテンプレート・イメージにサンプリングして、サムネイル・イメージを作成しています。 サムネイル・イメージを元のファイルに書き戻し、イメージの内部表現を解放しています。
db_insert_thumbnail()関数の既存のコードは、以前の実装と同様に、データベースにイメージ・ファイルをアップロードします。
ブラウザに次のURLを入力して、アプリケーションの変更をテストします。
Windowsの場合:
http://localhost/chap7/anyco.php
Linuxの場合:
http://localhost/~<username>/chap7/anyco.php
「Departments」ページで、「Show Employees」をクリックして、「Employees」ページにナビゲートします。

「Employees」ページで、新しい従業員レコードを挿入するには、「Insert new employee」をクリックします。

新しく従業員の詳細を入力するか、または表示されている値を使用します。従業員イメージを参照するには、「Browse」をクリックします。

サイズが100ピクセルより大きいJPEGイメージを検索して選択し、「Open」をクリックします。

「Insert New Employee」ページで、「Save」をクリックします。

「Employees」ページに、新しくアップロードしたJPEGイメージが表示されます。そのイメージ・サイズは、イメージ・サイズ変更コードを含める前にロードしたイメージと比較すると小さくなります。
