Mi in progress

研究者ではなく、エンジニアになることを決意した人のブログ。

学びことが多すぎて何から手を出していいのかわからない状況を打破したい

 

最近の課題感

お久しぶりです。 

前回のTwitter課題修正プロジェクトからまたしても時間が空いてしまいました...

それには、最近学びたいことが多すぎて何から手を出していいのかわからない状況が続いているという背景があります。

予定のない土日はとりあえず家に引きこもって参考書を読んだりコーディングしたりしていたのですが...正直その時思いついたことベースで勉強しちゃってます。なのでブログ更新もおざなりになっていました。 

エンジニアになる夢を叶えることができて夢心地な反面、どうすれば成長していけるのか、どんなキャリアを歩んでいけばいいのか、漠然とした不安があり、手当たり次第勉強しているという状況です。とにかく暇な時はプログラミングに関係することを優先順位を付けることなくやってました。これがいけなかった。

実はこれ、単純に勉強方法としてダメなだけでなく、イベントや遊びの予定を立てるのにも悪影響を及ぼしていることに気がつきました。

「イベントに行くより家に引きこもって勉強しよう」

みたいな強迫観念が己の中に生み出されるのです。

  

解決策

というわけで手始めに、

 ・なりたい像を明確にし、そこに向けて学ぶことに優先順位を付ける

 ・学んだことを記事としてまとめておく

をしようと思いました。というのも、ふわふわしているときって大抵、

 ・ゴールを明確にしていない (どこに向かえばいいのかわからない、行動指針がないので行動できない)

 ・現状の記録や振り返りができていない (ゴールという大きな山があったとして、今何合目に自分がいるのか認識できていない)

だと思うので。

 

特に現状の振り返りは見逃されがちではないでしょうか?

私はついつい教科書や記事を読んで終わってしまっています。

もっとひどいときは、Twitterにシェアしただけで満足しちゃったり...!

せめて「わかったこと・わからなかったこと・思ったこと」は記録したいです。記録します。

 

具体的TODO

1.なりたい像を明確にする

→ これは会社が提供しているスキルマップがあるので、それができるようになることを目標にします。◯と×をつけて、現状を把握します。

 

2.優先順位をつける

→ ×を◯にすることを最優先課題にします。

 

3.何をすれば達成できるのか、勉強方法を考える

→ 具体的なタスクに落とし込みます。

 

4.振り返りをする

→ 「やったこと・わかったこと・わからなかったこと・思ったこと」のテンプレートでブログに記録していきます。

 

今日は1・2・3をやります。

 

 

Twitter課題修正プロジェクト - 認証・認可・OAuth2.0の復習をしよう

お久しぶりです。

つい先日、会社の研修が全て終わって業務が始まりました。

前回の記事で、JavaとRustの違いについて学ぶと豪語したものの...研修課題が難しすぎて、プラスαで学ぶ余裕がありませんでした。宣言を守れていなくてごめんなさい。

Rustに関しては技術書典3で記事を寄稿すると決めたので、そこに向けて勉強を再開するつもりです。

追い風と勝手に感じたのですが、ついにオライリーからRustの本がでるみたいです!

日本語訳出ないかな... 

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

 

 ---

余談はこれくらいにして、本記事の本題に移ります。

研修最後の課題がTwitter実装だったのですが、動けばいいだけのゴリゴリコーディングをしてしまいました。お師匠に教えていただいた内容をキャッチアップしきれていない状態なので、空き時間にリファクタリングを進めていきたいと思います。

このプロジェクトのゴールは個人用のAWSTwitter課題を公開し、社外の友達に見てもらうことです!

まずは認証部分のリファクタリングを行います。

 

使っているツール(前提条件)
  • Spring boot
  • Spring security
  • Java 8
  • Docker (mysql 5.6)
  • Flyway

 

どんな風に現状のコードが酷いのか?(自己分析)
  • そもそも認証、認可、OAuth2.0のことをよく理解していない
  • AbstractPreAuthenticatedProcessingFilterのことをよく理解しないまま実装に使った
  • 他のControllerが@RestControllerなのに、なぜか認証に関するControllerだけ@Controllerになっている
  • ユーザー名とパスワードの照合ができたときにアクセストークンを発行するのだが、jsonでクライアント側に返すのではなく、ヘッダーに入れて返している(お作法的にとっても気持ち悪いとのこと...)

 

どう直していくか
  1. 認証認可について理解を深める
  2. OAuth2.0について理解を深める
  3. AbstractPreAuthenticatedProcessingFilter使用例を見て、お作法を学ぶ
  4. 設計図を書く
  5. 見積もりをする
  6. 実装

 

認証認可について理解を深める

早速、認証認可についての理解を深めていきたいと思います。

「認証認可って何が違うんだ...一緒じゃないの?」

そんな迷える子羊だった私を救ってくれた記事がこちらでした。

dev.classmethod.jp

認証 ... 通信の相手が誰(何)であるかを確認すること

認可 ... とある特定の条件に対して、リソースアクセスの権限を与えること

普段よく使っているTwitterFacebookは、認証(ユーザー名とパスワード照合で本人であることを認める)と認可(本人として、投稿やいいね等ができるようになる)が同時に行われているものだったので、疑問が浮かんでしまったんですね。

 

OAuth2.0についての理解を深める

自作Twitterのログイン・ログアウト実装の際、

「今回は認可サーバーとリソースサーバーを分けないけど、OAuth2.0のResource Owner Password Credentials Flowの考え方で、APIへのアクセストークンを発行してみよう」

というお達しをもらったのですが、「ログインといえばCookieやセッション」しか知らなかったので、初めて教えて頂いた時に頭がパンクしたのを覚えています。

改めてOAuth2.0について理解を深めていきます!

まずは、OAuthが必要になった背景についてですが、wikipediaに端的にまとめられていました。

マッシュアップによるWebサービスの連携が増え、デジタルアイデンティティの共有が問題となってきた。OpenIDのような連合アイデンティティが解決策として登場したが、これはIDの持ち主による認証手段であって、それによってどのリソースにアクセスできるかという認可については扱っていない。あるWebサービスAにユーザーの個人情報があるとき、そのWebサービスAと別のWebサービスBが連携し、WebサービスAにある個人情報をWebサービスBが自由にアクセスできる状況は好ましくない。そのため、WebサービスAPIへのアクセスを認可する手段が必要とされていた。

続いて、Resource Owner Password Credentials Flowについてです。これについては、素晴らしいQiitaの記事で学ばさせて頂きました。

qiita.com

ここで疑問に思ったのが、「Resource Owner Password Credentials Flowだと、アプリ側がusernameやpasswordを持つことになってしまうけど、いいのかな?」ということです。このような疑問について、RFC 6749にこのようなことが書いてありました。

The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application.

It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token.

つまりこのフローは、クライアントが極めて信頼できる場合もしくはOAuthへ移行する場合に有効だということです。

今回のTwitter課題においては、「移行」というより「拡張性」という言葉が適切かもしれません。

「今はusernameもpasswordも自分たちのサーバーで管理しているけど、いつかは他のサービスに認証部分を任せるかもしれない。」

「他のサービスを使っているユーザー情報で認証するようになるかもしれない。」

そういった場合にこのフローをあらかじめ採用しておけば、一から新たに認証・認可に関する部分を作る必要がありません。

ソフトウェアの拡張性を高めるために、お師匠はResource Owner Password Credentials Flowを採択したのだと理解できました。...合ってるかな?笑

あとで確認します。

 

今日はここまで。

次回はAbstractPreAuthenticatedProcessingFilterの使用例を見て、お作法を学んでいきます。

 

 

JavaとRustの違いをひよっこエンジニアが比較していきます(予告)

お久しぶりです。
最後のブログ更新から時間が経ってしまいましたが...元気に毎日を過ごしています。
4月から新卒エンジニアとして某IT企業に入社、毎日もりもりコードを書いていますが...
アウトプットサボり過ぎじゃない?
ということで、ブログ更新をまた始めようと思い立ちました。
物書きの肩慣らしに、JavaとRustの比較をしていこうと思います。


なぜJavaとRustなのか

弊社の新卒エンジニアは、経験者と未経験者がちょうど半々くらいの割合です。
経験者の子たちはどんどん次の研修に進んでいるし、未経験者の子たちも地頭の良さでどんどん研修をこなしている...
一方私は研修課題を理解するのに精一杯で、未経験者を脱却できない己に苛立ちを覚えるようになってきました。
もっとJavaを使えるようになりたい。
具体的には、

  • 動けばいいや
  • IDE(IntelliJ IDEA)がサジェストしているから書き換えよう
  • 先輩が言っているからとりあえず直そう

という状況を打破したいです。
そのためには、文法やメソッドを覚えるだけでは足りない、Javaの設計思想や哲学を学ぶ必要があると思いました。
しかしながら、その必要性はわかるものの具体的にどう学べばいいのかさっぱりでした。

そんなときに出会ったのがRustというプログラミング言語です。
Rustの教材を読んでいて、

という疑問が浮かんできました。
違う言語に触れたことで「これはJavaの特徴なのか」という気づきを得たわけです。

私はまともに学び始めたものがJavaくらいなので他の言語はよく知らないのですが、Rustの教材には、

  • 初心者向け教材で隠蔽されがちな専門用語が登場する
  • Rustを開発している意義がはっきりと書かれている
  • 多言語との違いを明記してくれている

ので、個人的には設計思想や哲学を学ぶ上でも良い教材になりそうだなと感じました。


プログラマが知るべき97のこと

また、この本もJavaとRustを比較しようと思うきっかけになりました。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

こちらの本でアンダース・ノラスさんが仰っていることにグッと心を惹かれました。

新しい言語を学び、その勘所をつかんだら、前から知っていた言語の使い方がそれまでと変わっていることに気づき、自分で驚くことがよくあります。

 

複数の言語について学ぶと、デザインパターンについての理解も深まります。

いろんな言語の勘所をつかんで、デザインパターンへの理解を深めていきたい!

そんなわけで、JavaとRustの違いをこれから記事にしていこうと思いました。
相当勉強しないと書けない記事なので、気合い入れて勉強していきます。

Cloud9でPDO接続をする方法

お久しぶりです。
気づいたら一ヶ月も空いてしまいました。
今日はCloud9でPDO接続する方法について書きたいと思います。

 

Cloud9とは

Cloud9とは、先日Amazonに買収された統合開発環境Webサービスのことです。Ruby On RailsやWord Pressなど、主要なフレームワークを簡単に利用することができます。Apache起動もワンクリックで行うことができ、サービス開発のトラインアンドエラーの強い味方です。

 

PDO接続とは

PDOとは、ブラウザとmysqlのデータベースを繋ぐPHPのクラスのことです。このクラス内のメソッドを用いることで、例えばメッセージフォームの内容をデータベース取り込むことができます。mysql上の特定のデータベースを指定し、編集を許可されたユーザーとしてログインするためのプログラムがPDO接続です。

 

問題提起

PDO接続には、サーバー名、ユーザー名、パスワード、データベース名などの情報が必要です。普段私はさくらVPSサーバー上でmysql+PHPwebサービスを開発しているのですが、cloud9上ではこれらの情報はどう書けばいいのかわからず非常に手こずりました。一応公式コミュニティページに方法が載っているのですが、mysqliクラスを用いているため、PDOクラスを用いたい私のニーズにはマッチしませんでした。

 

解決方法

こちらの記事を参考にしつつ、書いてみました。 qiita.com

index.php


define('DSN', 'mysql:host=127.0.0.1;port=3306;dbname=データベース名;charset=utf8;');
define('DB_USER', 'C9_USER');
define('DB_PASSWORD', '');

try{
$dbh = new PDO(DSN, getenv(DB_USER), DB_PASSWORD);
} catch (PDOException $e) {
print('Error:'.$e->getMessage());
die();
}

 

ポイント

・ホスト名とポート名が公式から指定されているものがある
・パスワードは無い(シングルクォーテーション2つ)
・DE_USER定数をgetenv関数に代入する

 

今日はこの辺で。これからもプログラミングの勉強頑張ります(*^^*)

 

PHPを用いて、MySQLのデータをGoogle Chart Toolsで描画してみました

お久しぶりです。気づいたら前回の投稿から3週間くらい経ってしまいました。

相変わらず、バイトでたくさんコーディングしています(`・ω・*)b

今日はタイトル通り、PHPMySQLからデータを引っ張ってきて、それをGoogle Chart Toolsと組み合わせてブラウザ上で描画した話です。検索しても古い記事しか出てこなくてかなり四苦八苦したので、今後の自分のためのメモとして、書くことにしました。

 

Google Chart Toolsとは - Charts  |  Google Developers

Googleが公開しているAPIで、これを用いればデータを簡単にブラウザ上で描画することが出来ます。JavaScriptで記述します。

 

目的

PHPを用いて、MySQLのデータをGoogle Chart Toolsで描画する

 

苦労したこと

・参考にしたこちらの記事

Google Chart Tools: How to create a line chart example with mySQL/PHP and JSON | Kometschuh - Blog

が、PHP 5.5.0 で非推奨になった拡張モジュールを用いており、PDO_MYSQLを用いた書き方に翻訳しなければいけなかったこと。

・データの格納を、Google Chart Toolsの書式にしなければならなかったこと。参考にしたこちらの記事

【PHP】MySQLに保存しているデータをJSONで吐き出す - Qiita

でデータを吐き出すと、

[{"date":"2016-04-01","A":"1890000","B":"784000","C":"0"},...

のように吐き出されてしまいます。Google Chart Toolsでは、データの書式が決まっていて、

['date', 'A', 'B', 'C'],

['2015-04-01', 1890000, 784000, 0],...

のようにしなければなりません。この書式変換も頭をかなり悩ませました。

 

実際のコード (※ PHP 5.3.3(cli), MySQL 5.1.73の環境です) 

functions.php

<?php

function connectDb( ) {
try {
array(PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/my.cnf',
PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'php',
);
return new PDO(DSN, DB_USER, DB_PASSWORD);
} catch (PDOException $e) {
echo $e->getMessage();
exit;
}
}

 

config.php

<?php
define('DSN','mysql:host=localhost;dbname=dbname;charset=utf8');
define('DB_USER','user');
define('DB_PASSWORD','pass');
error_reporting(E_ALL & ~E_NOTICE);

 

index.php

<?php
require_once('config.php');
require_once('functions.php');

mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");
?>

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>棒グラフ</title>
<style>
h1 {
color: #696969;
}
</style>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
google.load('visualization', '1', {packages:['corechart']});
google.setOnLoadCallback(drawChart);

// データ読み込み

function drawChart() {
var data = google.visualization.arrayToDataTable([
['日付(月単位)', 'A', 'B', 'C'],
<?php
// DBに接続
$dbh = connectDb();
// SQL
$sql = 'SELECT * FROM sales';
// クエリ
$stmt = $dbh->query($sql);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 行の長さ取得
$length = $stmt->rowCount();
// カウント
$no = 0;
foreach ($result as $value) {
echo '[\''.$value["date"].'\', '.$value["infra"].', '.$value["software"].', '.$value["web"].']';
$no++;
if ($no !== $length) {
echo ",\n";
}
}
?>
]);
var options = {
width:900,
height:600,
chartArea: {
top:80,
left:200
},
fontName: 'メイリオ',
backgroundColor:'#EFF4F5',
isStacked: true,
colors: ['#2E8EF6', '#DA3A29', '#8EC43C'],
bar: {groupWidth: 20},
hAxis:{
title:'日付(月単位)',
titleTextStyle: {
fontName: 'メイリオ',
fontSize: 16,
italic: false,
bold: false,
color: '#696969'
},
textStyle: {
fontSize:12,
color: '#696969',
fontName: 'メイリオ'
},
slantedText: true
},
vAxis:{
title: '合計',
titleTextStyle: {
fontName: 'メイリオ',
fontSize: 16,
italic: false,
bold: false,
color: '#696969'
},
textStyle: {
fontSize:12,
color: '#696969',
fontName: 'メイリオ'
}
},
legend:{
position: 'top',
textStyle:{
fontName: 'メイリオ',
color: '#696969',
fontSize: 16
}
}
};
var chart = new google.visualization.ColumnChart(document.getElementById('graph1'));
chart.draw(data, options);
}
</script>
</head>
<body>
<h1>サンプル棒グラフ</h1>
<div id="graph1"></div>
</body>
</html>

 

上のコードで以下のようなグラフができました!

f:id:mi_progress_oOo:20160803085909p:plain

 

今回のコーディングポイントは、$stmt->rowCount();で行の長さを取得して、if文で

「最後の行以外は最後に,(カンマ)を付けてね」という文章を書いたところです!最後の行は,(カンマ)がいらない(つけるとエラーを吐きます)ので、それをforeach文でどのように表すのか、ああでもないこうでもないと四苦八苦したのが今回一番楽しいコーディングでした(*°ω°*)

これからもプログラミングの勉強頑張ります!!!

 

clipboard.jsを使って、ColorImportCatchというWebアプリを作りました

今日は人生初のwebアプリを作りました。

その名もColorImportCatchです!

ColorImportCatch

 

1. 概要

ColorImportCatchは、

・最大10色のパレットを、HEXコードを入力するだけで見ることができる

・パレットをクリックするだけでクリップボードにコピーできる

というツールです。

f:id:mi_progress_oOo:20160710182945p:plain

 

2. 作ろうと思ったきっかけ

ボタンや背景などの色を微調整するとき、

「この前の前に書いてみたHEXコードの色がよかったな...あれ、どの色だっけ??」

「この絶妙な色の違いを比較したいな」

「色をクリックするだけでクリップボードにコピーできればいいのに...」

という思いが沸々と沸き起こりました。

 

実は、色をクリックするだけでクリップボードにコピーできるサイトはあります。

Flat UI Colors 

でも、自分でカスタマイズしたパレットの色をクリップボードにコピーできるサイトはありません。

 

なければ作ればいいじゃない。

 

というわけで作りました。

 

3. 作り方

先日のバイトで、「実装に悩んだ時は、出来そうな部分から作っていけばいい」ことを学びました。今回もこの学びを活かして開発を進めました。「指定した色のパレット表示」と、「そのパレットをクリックするとクリップボードにコピー」を同時に実装するのは難しそうだったので、まずは、

・HEXコードを入力すると、パレットを表示してくれるサイト

・パレットをクリックすると、そのHEXコードをクリップボードにコピーしてくれるサイト

をまずは別々に作ってみました。その後、この2つの機能をうまく合わせられるように微調整を行いました。

 

4. ハックした点

初心者の私が、「ここはちょっと頭使ったな」と思ったコードについてお話します。

(4-1) テキストボックスで入力したHEXコードを、指定場所の背景色にする

テキストボックスの値を取得するやり方は簡単に見つかりました。

[JavaScript] テキストボックスの値を取得する

問題は、この取得した文字をどのように指定場所の背景色のHEXコードにすればいいのか?ということです。取得した文字は、テキストボックスへの入力の度に変化する変数です。style属性で、background-color: AAA; (AAAは定義した定数)という書き方はできないし...どうすればいいのかな?としばらく悩みました。結論から言うと、全部javascriptで書きました。そのコードを以下に示します。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ColorInport</title>
<style>
.btn {
text-align: center;
width: 200px;
height: 400px;
display: table-cell;
vertical-align: middle;
}
</style>
</head>
<body>
<form name="form1" id="id_form1" aciton="">
<input name="textBox1" id="id_textBox1" type="text" value="">
<input type="button" value="Exec" onclick="onButtonClick();">
</form>
<div id="output" class="btn"></div>


<script type="text/javascript">
function onButtonClick() {
target = document.getElementById("output")
target.innerText = document.forms.id_form1.id_textBox1.value;
var color = target.innerText;
target.style.backgroundColor = color;
target.style.color = 'white';
}
</script>
</body>
</html>

 ポイントは、テキストボックスから取得した文字列を、変数colorで定義したことと、target.style.backgroundColor = color;で、taget(もとのもとを辿れば、id="output"で定義された場所のことです)の背景の色を変数colorにせよ、というコードにしたことです。これで無事、目的が達成されました。

 

(4-2) クリップボードにコピーを実装する

クリップボードにコピーを実装できるとても便利なプラグインを発見しました。

clipboard.js — Copy to clipboard without Flash

こちらのZIPファイルをDLして、デモのhtmlファイル(ルートディレクトリからのパス: clipboard.js-master/demo/target-input.html)を参考にしながら実装を行いました。

ここからがハックなのですが、パレットをクリックするとその色がクリップボードにコピーされるように見えるものの、実際にコピーしているのはテキストボックスの中身です。target-input.htmlでは、ボタンを押すとテキストボックスの中身がコピーされる仕組みなのですが、ボタンをパレットに置き換えてコーディングしてみました。

具体的には以下のとおりです(index.htmlは一部だけ掲載しています)。

index.html

<div class="form-float">

<form name="form1" id="id_form1" aciton="">
<input name="textBox1" id="id_textBox1" type="text" value="" class="textBox_style">
<input type="button" onclick="onButtonClick1();" class="btn-style">
</form>
<div id="output1" class="btn" data-clipboard-action="copy" data-clipboard-target="#id_form1"></div>
</div> 

 

catch.js

var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) { console.log(e); });
clipboard.on('error', function(e) { console.log(e); });

という感じです。

 

生まれて初めて、構想から実装まで一人でやった記念すべきwebアプリです。

めちゃくちゃ楽しかったです!!!!!!!

もっと高度なアプリが作れるように、これからもプログラミングの勉強頑張ります(`・ω・)b 

2016 06 29 の学び - CSVファイルのGUIインポート-エクスポートツールを実装した

方向を見失いそうになってたので、まずは目標を簡略化しました。

 

(1) 目標の簡略化

"ユーザーは「ファイルを選択する」ボタンを押すとファイル選択ウィンドウが出てきてファイルを選べる。CSVファイルを選択して、「アップロード」ボタンを押すと裏でsample.shが動き出し、様式の整った新しいCSVファイルが自動的にユーザーのPCへダウンロードされる。"

(簡略化1) ユーザーがブラウザ上で選択したファイルを、会社サーバーの指定したディレクトリへ保存できる仕組みを実装しよう。

(簡略化2) シェルスクリプトをブラウザ上で実行しよう。

(簡略化3) 会社サーバー内にあるファイルを、ユーザーがブラウザ上からダウンロードできる仕組みを実装しよう。

(簡略化4) 上記3つをまとめてみよう。

全部一気に考えるのではなくて、全部小分けしてみることにしました。

 

(2) 簡略化1について

(2-1) 参考サイト

ファイルのアップロード | PHP Labo

 

(2-2) やったこと

(2-2-1) htmlでフォーム定義

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>sample</title>
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
csvファイルをアップロードして下さい<br><br>
<input type="file" name="upfile" size="30"><br>
<br>
<input type="submit" value="アップロード">
</form>
</html>

form タグの method を post にし、enctype を multipart/form-data にすると、ファイルをアップロードすることができるんですね。このenctype="multipart/form-data"に関して素晴らしい記事を見つけたので、貼っておきます。

enctype='multipart/form-data'ってなんだ? - MUGENUP技術ブログ

こういう記事大好きです。

 

(2-2-2) phpでデータ受信

upload.php

<?php

if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {

if (move_uploaded_file($_FILES["upfile"]["tmp_name"], "import/" . $_FILES["upfile"]["name"])) { chmod("import/" . $_FILES["upfile"]["name"], 0777);

echo $_FILES["upfile"]["name"] . "をアップロードしました。”;

} else {

echo "ファイルをアップロードできません。”; }

} else {

echo "ファイルが選択されていません。”;

}

?>

php不慣れなので以下に訳しました。

(訳) is_uploaded_file関数で、ファイルがアップロードされたか確かめよ。これができなかったら、「ファイルが選択されていません」と表示せよ。mova_uploaded_file関数で、一時的にサーバー上に保存されたファイルを、importという名前のフォルダに移し、オリジナルのファイル名で保管せよ。chmod関数でパーミッションの管理を777に指定せよ。以上がうまくいかなかったら、「ファイルをアップロードできない」と表示せよ。 

以上で無事、ブラウザ上からファイルをアップロードできるようになりました。

 

(3) 簡略化2について

(3-1) 参考サイト

phpでシェルファイルを実行する | hacknote

 

(3-2) やったこと

シェルスクリプト実行用のデモファイルを作りました。

index.php

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>test shell</title>

</head>

<body>

<h1>シェルスクリプト実行</h1>

<?php

$output = shell_exec("sh ./sample.sh");

?>

</body>

</html>

このページを開くと、ちゃんとシェルスクリプトが実行されていました。

 

(4) 簡略化3について 

(4-1) 参考サイト

readfile: ファイルを出力する (ファイルシステム 関数)

 

(4-2) やったこと

こちらも(3)同様、デモファイルを作りました。

export.php

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>export test</title>

</head>

<body>

<h1>ファイルをダウンロードします。</h1>

<?php

$file = 'export/sample.csv';

if (file_exists($file)) {

  header('Content-Description: File Transfer');

  header('Content-Type: application/octet-stream');

  header('Content-Disposition: attachment; filename='.basename($file));

  header('Content-Transfer-Encoding: binary'); header('Expires: 0');

  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');

  header('Pragma: public');

  header('Content-Length: ' . filesize($file));

  ob_clean();

  flush();

  readfile($file);

  exit;

}

?>

</body>

</html>  

できました。よっしゃー!

 

(4) 簡略化4について

あとはこれら3つを1つにまとめる作業です。さらにもう一つやらないといけないことが...指定するファイル名の変数化です。どういうことかと言うと、

・a.csvが指定されたら、a.shシェルスクリプトが実行されて、aexp.csvが出力される

・b.csvが指定されたら、b.shシェルスクリプトが実行されて、bexp.csvが出力される

・c.csvが指定されたら、c.shシェルスクリプトが実行されて、cexp.csvが出力される

このa, b, cの部分を変数化したいという訳です。

 

ファイル名は、$_FILES["upfile"]["name"]で取得できますが、これをechoすると、

a.csv

.csvまで取得されてしまいます。ここを消したいので、

$filename=$_FILES["upfile"]["name"];

$cut=4;

$replace = substr($filename , 0 , strlen($filename)-$cut);

と書きました。(参考: [PHP] 文字列の前後から指定した数の文字を削除する)

今回これを実装できたことが一番嬉しかったです!

あとは、1つにまとめる作業ということで、index.htmlから情報を渡すupload.phpを次のように書きました。

upload.php

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>sample</title>

</head>

<body>

<p>

<?php

if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {

  if (move_uploaded_file($_FILES["upfile"]["tmp_name"], "import/" .  

    $_FILES["upfile"]["name"]))

    { chmod("import/" . $_FILES["upfile"]["name"], 0777);

    echo $_FILES["upfile"]["name"] . "をアップロードしました。";

    $filename=$_FILES["upfile"]["name"];

    $cut=4;

    $replace = substr($filename , 0 , strlen($filename)-$cut);

    $output = shell_exec("sh shell/".$replace."import.sh");

    $file = 'export/'.$replace.'export.csv';

    if (file_exists($file)) {

    header('Content-Description: File Transfer');

    header('Content-Type: application/octet-stream');

    header('Content-Disposition: attachment; filename='.basename($file));

    header('Content-Transfer-Encoding: binary');

    header('Expires: 0');

    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');

    header('Pragma: public');

    header('Content-Length: ' . filesize($file));

    ob_clean();

    flush();

    readfile($file);

    exit;

    }

    } else {

    echo "ファイルをアップロードできません。";

    }

    } else {

    echo "ファイルが選択されていません。";

   }

?>

</p>

</body>

</html>

実装キタ━━━━(゚∀゚)━━━━!! 

めちゃくちゃ嬉しかったです。

自分がこのようなGUIを作れるようになるなんて夢のようでした。

書いたコードが正常に動き出すのは、最高に気持ちがいいです!

 

これからもプログラミングの勉強頑張ります!