60歳お婆ちゃんプログラムに挑戦してみた
60歳を間近にウェブデザイナーを目指して独学で勉強しているお婆ちゃんです。
去年の暮れからphpを勉強して、初めてシステムらしきものを作ってみました。
・やりたいこと プチ・クラウドストレージ
ファイルをどこからでもアップ、保管してダウンロードもできる。
セキュリティも兼ねてIDとパスワードでログイン形式にする。
まずはパワーポイントでサイトの系図を設計しました。
Excel、Word、パワポは商工会議所で習いたてホヤホヤです。
それぞれ基礎編までクリアして一ヶ月半くらいかかりました。
全部で5万円くらいはかかったかな。
次は手順を考えてイメージを具体化
これはAdobeのXDを使ってみました。
もうお金がないので無料版。
操作も簡単で、習わなくても感覚的に作れちゃうので便利です。
ページ自体はシンプルにしたかったのでフォントだけで作りました。
コードを書くのもAdobeの無料Brakets。Adobeドップリ。
ログインページ
パスワードとIDはここで決めてます。
空文字はNGの条件も設定。
・login.php
//XSS
function html_escape($word){
return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
}
$logid = '';
$pass = '';
$messege = '';
if($_SERVER['REQUEST_METHOD'] === 'POST'){
//isset入れると空文字条件が効かない
$logid = $_POST['logid'];
$pass = $_POST['pass'];
$logid = html_escape($logid);
$pass = html_escape($pass);
//IDとパスワード設定
if($logid === '' && $pass === ''){
session_start();
$_SESSION['login'] = 1;
//ファイル一覧へリロード
header('Location: file_list.php');
exit();
} elseif ($logid === '' || $pass === ''){
$messege = '<p class="notice">IDとパスワードを空文字にしないで入力してください</p>';
} else {
$messege = '<p class="notice">IDかパスワード、もしくは両方違います</p>';
}
}
?>
<!doctype html>
<!-- headerインクルード -->
<?php require_once(dirname(__FILE__).'/header.php'); ?>
<div id="wrapper">
<header>
<div id="titleVar">
<h1>ファイル預かり処 マイ保管庫</h1>
<p class="tx14">ログインページ</p>
</div>
<div id="topvew">My keep folder</div>
</header>
<main id="topMain">
<form class="clearfix" action="" method="post">
<label>ログインID</label>
<input name="logid" type="text" />
<label>パスワード</label>
<input name="pass" type="password" />
<p id="logBtn"><input type="submit" value="ログイン" /></p>
<?php echo $messege; ?>
</form>
</main>
<!-- footerインクルード -->
<?php require_once(dirname(__FILE__).'/footer.php'); ?>
</div>
ファイルリスト一覧ページ
アップロードとダウンロード、削除ファイルの3つのform
アップロードは同一ページで処理
ダウンロードはチェックページに飛ばしてリロード処理
削除ファイルは確認ページを別に作ってpostデータを渡す
ちなみにダウンロードと削除ファイルはタブ切替。
フォルダーの中身は一緒でアップすると自動でリストが増えて、削除すると減っていきます。
・file_list.php
//ログインしていないとアクセスさせない
session_start();
session_regenerate_id(true);
if(isset($_SESSION['login']) === false){
header('Location: un_login.php');
exit();
}
function html_escape($word){
return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
}
$up_file = '';
$messege = '';
$select_file = '<p id="take">ファイルを選択して下さい</p>';
$restore = '';
$up_before = 'upBefore';//非表示css
$filename = '';
if($_SERVER['REQUEST_METHOD'] === 'POST'){
$up_file = $_FILES['file_up'];
$up_file['name'] = html_escape($up_file['name']);
$up_file['name'] = strtolower($up_file['name']);//英小文字に変換
//var_dump($up_file['name']);
$extension = Pathinfo($up_file['name'],PATHINFO_EXTENSION);//.以降の拡張子を重複しないよう整形
$filename = Pathinfo($up_file['name'],PATHINFO_FILENAME);
$filename = str_replace('.', '', $filename);//ファイル名に.があったら除去
//ファイルがNGの場合条件処理
if($up_file['size'] > 30000000 ){
$messege = '<p id="caution" class="notice"><i class="fas fa-info-circle"></i>ファイルサイズが容量を超えています</p>';
$up_before = 'upBefore';
$restore = '<a id="restore" href="file_list.php">こちらからUPし直してください</a>';
$select_file = '';
//phpよりエラー表示を出すときsubmitのvalue値を空文字に
} else {
$messege = '';
$up_before = 'upAfter';
//fileをアップする関数
move_uploaded_file($up_file['tmp_name'], './up_file/'.$filename.'.'.$extension);
}
}
//upフォルダの中身
$dw_items = glob('./up_file/*');//DL用、同じでも変数変えないとエラーになる
$del_items = glob('./up_file/*');//削除用、grobは配列形式でファイルパスを取得
?>
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ファイル一覧 | ファイル預かり処・マイ保管庫</title>
<!-- headerインクルード -->
<?php require_once(dirname(__FILE__).'/header.php'); ?>
<div id="wrapper">
<header>
<div id="titleVar">
<h1><i class="fas fa-circle"></i>ファイル預かり処 マイ保管庫</h1>
<p id="logout"><a href="logout.php">ログアウト</a></p>
</div>
<div id="topvew">My keep folder</div>
</header>
<main id="main">
<h2 class="pageTitle">ファイルアップロード</h2>
<!-- ファイルup -->
<form id="upBox" action="" method="post" enctype="multipart/form-data">
<p class="notice">※ファイルsizeは1つにつき30MBまで、名前は英小文字で</p>
<!-- UPし直し表示 -->
<?php echo $restore; ?>
<p id="<?php echo $up_before; ?>">ファイル「<?php echo $filename; ?>」はアップされました。続けてUPできます</p>
<label for="up">
<!-- ファイルを選択ボタン -->
<?php echo $select_file; ?>
<input id="up" type="file" name="file_up">
</label>
<p id="send"><input type="submit" value=""></p>
<!-- エラーメッセージ -->
<?php echo $messege; ?>
</form>
<div id="fileBox">
<p id="fileCount">ファイル数<?php echo count($dw_items); ?>項目</p>
<h3 class="selectFile" id="dowTab">DL用ファイル一覧</h3>
<form id="dowList" action="download_file.php" method="post">
<!-- 飛び先でLocation リダイレクト処理-->
<ul>
<?php if(count($dw_items) === 0): ?>
<li>まだファイルはありません</li>
<?php else: ?>
<?php foreach($dw_items as $items): $dw_name = Pathinfo($items,PATHINFO_BASENAME); ?>
<li><input type="radio" name="dowl" value="<?php echo $dw_name; ?>"><?php echo $dw_name; ?></li>
<?php endforeach; ?>
<?php endif; ?>
</ul>
<p class="notice">※左のラジオボタンにチェックしてダウンロードボタンをクリックしてください</p>
<p class="pibtn"><input type="submit" value="Download"></p>
</form>
<h3 class="selectFile" id="delTab">削除用ファイル一覧</h3>
<form id="delList" action="delete_confilm.php" method="post">
<ul>
<?php if(count($dw_items) === 0): ?>
<li>まだファイルはありません</li>
<?php else: ?>
<?php foreach($del_items as $items): $del_name = Pathinfo($items,PATHINFO_BASENAME); ?>
<li><input type="checkbox" name="del[]" value="<?php echo $del_name; ?>"><?php echo $del_name; ?></li>
<?php endforeach; ?>
<?php endif; ?>
</ul>
<p class="notice">※左のチェックボックスを選択(複数可)して確認ボタンをクリックしてください</p>
<p class="vibtn"><input type="submit" value="削除確認"></p>
</form>
</div><!-- //id="fileBox"-->
</main>
<!-- footerインクルード -->
<?php require_once(dirname(__FILE__).'/footer.php'); ?>
input type="file"は特殊でデフォルトのボタンを使うのはビジュアル面で抵抗があったのでカスタマイズしました。
ファイルが選択されたらボタンがファイル名に変わって、エラーだったら上にメッセージ表示。
OKだったらtype="file"ブロックは非表示になって、type="submit"にすり替え。
見た目は一緒のボタンです。
ファイルアップが成功したらボタンの上にファイル名が表示して下のリストに追加といった仕様。
ただ、ファイル選択時はsubmitボタンは押されてないのでphpでの処理が難しい。
そこでjsのchangeイベントを活用。
ここは頭がこんがらがりました。phpとjsとcssのトリプル連携。
jQuery('#up').on('change',function(){ const upfile = jQuery('#up').get(0).files; console.log(upfile); const fileName = upfile[0].name; //file選択をsubmitにすり替え jQuery('#take').css('display','none'); jQuery('#send').css('display','block'); jQuery('#send input').val(fileName); });
ダウンロードチェックページ
ダウンロードのコードはどうしても分からなかったのでググって動いたものをコピペさせてもらいました。
それまではダウンロードできても開けられなかったり不具合続出でした。
ここのコードが一番難しい。
今の段階では理解できなかったのですが、そのうち自分でも組めるようになりたいです。
・download_file.php
//ダウンロードチェック
session_start();
session_regenerate_id(true);
if(isset($_SESSION['login']) === false){
header('Location: un_login.php');
exit();
}
function html_escape($word){
return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
}
$dowload_file = $_POST['dowl'];
$dowload_file = html_escape($dowload_file);
//var_dump($dowload_file);
//ダウンロードできなかったのでネットから拾ってきた
function download($pPath, $pMimeType = null){
//-- ファイルが読めない時はエラー(もっときちんと書いた方が良いが今回は割愛)
if (!is_readable($pPath)) { die($pPath); }
//-- Content-Typeとして送信するMIMEタイプ(第2引数を渡さない場合は自動判定) ※詳細は後述
$mimeType = (isset($pMimeType)) ? $pMimeType
: (new finfo(FILEINFO_MIME_TYPE))->file($pPath);
//-- 適切なMIMEタイプが得られない時は、未知のファイルを示すapplication/octet-streamとする
if (!preg_match('/\A\S+?\/\S+/', $mimeType)) {
$mimeType = 'application/octet-stream';
}
//-- Content-Type
header('Content-Type: ' . $mimeType);
//-- ウェブブラウザが独自にMIMEタイプを判断する処理を抑止する
header('X-Content-Type-Options: nosniff');
//-- ダウンロードファイルのサイズ
header('Content-Length: ' . filesize($pPath));
//-- ダウンロード時のファイル名
header('Content-Disposition: attachment; filename="' . basename($pPath) . '"');
//-- keep-aliveを無効にする
header('Connection: close');
//-- readfile()の前に出力バッファリングを無効化する ※詳細は後述
while (ob_get_level()) { ob_end_clean(); }
//-- 出力
readfile($pPath);
//-- 最後に終了させるのを忘れない
exit;
}
//選択されたファイルがあったらダウンロード、なかったらそのままリダイレクト
if(isset($_POST['dowl'])){
download('./up_file/'.$dowload_file);
header('Location: file_list.php');
} else {
header('Location: file_list.php');
}
削除確認、完了ページ
削除だけは誤って消してしまって後悔しないように、確認してからの動線にしました。
・delete_done.php
//ログインしていないとアクセスさせない
session_start();
session_regenerate_id(true);
if(isset($_SESSION['login']) === false){
header('Location: un_login.php');
exit();
}
function html_escape($word){
return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
}
$delete_file = '';
//POSTで渡されたファイルを削除
if(isset($_POST['check'])){
for($i = 0; $i < count($_POST['check']); $i++){
unlink('./up_file/'.html_escape($_POST['check'][$i]));
//削除ファイルli書出し
$delete_file .= '<li><i class="far fa-file"></i>'.html_escape($_POST['check'][$i]).'</li>';
}
}
?>
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ファイル削除完了 | ファイル預かり処・マイ保管庫</title>
<!-- headerインクルード -->
<?php require_once(dirname(__FILE__).'/header.php'); ?>
<div id="wrapper">
<header>
<div id="titleVar">
<h1><i class="fas fa-circle"></i>ファイル預かり処 マイ保管庫</h1>
<p id="logout"><a href="logout.php">ログアウト</a></p>
</div>
<div id="topvew">My keep folder</div>
</header>
<main id="confiBox">
<h2 class="pageTitle">ファイル削除完了</h2>
<p class="confiText">以下のファイルを削除しました</p>
<ul>
<?php echo $delete_file; ?>
</ul>
<p id="toListpage"><a href="file_list.php">ファイル一覧ページへ</a></p>
</main>
<!-- footerインクルード -->
<?php require_once(dirname(__FILE__).'/footer.php'); ?>
完成したのであとは実際のサーバに上げて動作確認。
動いた時は大感動。
あれ?
でもアップできないファイルがある。
色々試して、どうやら日本語名のファイルはアップできないみたい。
XAMPP開発時では日本語のファイル名でも大丈夫だったんですけどね。
そういえば日本語とサーバの相性は良くないと昔から言われてました。
とりあえず注意書きに日本語NGと追加して応急対処。
preg_matchで条件設定した方がいいのかなと思ったりしています。
ひとまず、これで完成として使い込んでみようと思ってます。
お婆ちゃんのweb制作奮闘記でした。