備忘録

webの備忘録のために

Laravel 整理その1

Laravelのディレクトリ構成

とりあえず色々とフォルダはあるけれど、 以下のものが基本的な部分で覚えておけばおーけ。

1. /.env (環境設定)
2. /config/app.php (アプリケーション 基本設定)
3. /routes/web.php (ルート定義)
4. /resources/views/ 以下 (ビュー・HTML などの表示要素を設定)
5. /app/Http/Controllers/ 以下 (コントロール/モデルを設定)

DBの設定としては.envフォルダにDBの設定等ができるようになっているので、
そこで設定。(今回のcloud9では最初からDB環境も用意されてる)

で、一旦今回は簡単な本の管理アプリを作ってみる。

取り敢えずデータベースの定義をするために
データベースマイグレーションを実行。コマンドは以下
php artisan make:migration ファイル名 --create=テーブル名

で、生成された/cms/database/migrations
のファイルに必要なカラム等を設定してく。

「up」メソッドは新しいDB、インデックス、カラムを追加するもの
「down」メソッドはupメソッドで作成したものを消す。

Laravel5.4以上には
「/app/Providers/ AppServiceProvider.php
のファイルには以下の設定をする。

use Illuminate\Support\Facades\Schema;
Schema::defaultStringLength(191);

こちらは
Laravel5.4 以上から標準charasetがutf8mb4に変更され、
標準のvarchar(255)設定が実行されるとCloud9のMySQL バージョンではエラーになる。
上記のコードで、 varchar(191)に変更することで解消している

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    use Illuminate\Support\Facades\Schema;

    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

upメソッドに必要なカラム等を追加したら
php artisan migrate
を実行してDBを定義する。

laravelを触ってみる 導入

Laravelを今更ながらに触ってみる。

と、思って環境を用意しようと思ったのだがどうせなら試してみようと思っていたcloud9で 環境を構築しようかと思った。

https://c9.io/

使い方は単純明快。登録作業はいるが、登録が終わったらプロジェクトを立ち上げるだけ。

f:id:the_cabs:20180726000425j:plain

Choose a templateは自分の開発する環境に合わせて選択(今回はphp)。 これで利用したい言語の開発環境を整えてくれる。

で、実際にLaravelを導入するために状態を確認してみるとphp(5.5.9)もインストールされてるし、 composerも初期からしっかりインストールされてある状態だった。 便利すなぁ。

しかしLaravelの最新は5.6はphp7.1以上が必須。 なのでとりあえず7.1にアップグレードをするために以下を実行。

sudo add-apt-repository ppa:ondrej/php

sudo apt-get update

sudo apt-get install libapache2-mod-php7.1

sudo a2dismod php5

sudo a2enmod php7.1

sudo apt-get install php7.1-dom php7.1-mbstring php7.1-zip php7.1- mysql php7.1-sqlite

phpのバージョンを確認してみるとしっかりphp7系に。

それかとりあえずLaravelのインストールを実行。

インストーラーを用意して・・・ composer global require "laravel/installer"

プロジェクトを作成。 composer create-project laravel/laravel cms

とりあえず開発環境は整った。

f:id:the_cabs:20180726000448j:plain

画像ファイルアッププログラム

簡単な画像ファイルアッププログラム。

index.php

<?php

ini_set('display_errors', 1);
define('MAX_FILE_SIZE', 1 * 1024 * 1024); // 1MB
define('THUMBNAIL_WIDTH', 400);
define('IMAGES_DIR', __DIR__ . '/images');
define('THUMBNAIL_DIR', __DIR__ . '/thumbs');

if (!function_exists('imagecreatetruecolor')) {
  echo 'GD not installed';
  exit;
}

function h($s) {
  return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}

require 'ImageUploader.php';

$uploader = new \MyApp\ImageUploader();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $uploader->upload();
}

$images = $uploader->getImages();

?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Image Uploader</title>
  <style>
  body {
    text-align: center;
    font-family: Arial, sans-serif;
  }
  ul {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  li {
    margin-bottom: 5px;
  }
  </style>
</head>
<body>

  <form action="" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo h(MAX_FILE_SIZE); ?>">
    <input type="file" name="image">
    <input type="submit" value="upload">
  </form>

  <ul>
    <?php foreach ($images as $image) : ?>
      <li>
        <a href="<?php echo h(basename(IMAGES_DIR)) . '/' . basename($image); ?>">
          <img src="<?php echo h($image); ?>">
        </a>
      </li>
    <?php endforeach; ?>
  </ul>

</body>
</html>

ImageUploader.php

<?php

namespace MyApp;

class ImageUploader {

  private $_imageFileName;
  private $_imageType;

  public function upload() {
    try {
      // error check
      $this->_validateUpload();

      // type check
      $ext = $this->_validateImageType();
      // var_dump($ext);
      // exit;

      // save
      $savePath = $this->_save($ext);

      // create thumbnail
      $this->_createThumbnail($savePath);

    } catch (\Exception $e) {
      echo $e->getMessage();
      exit;
    }
    // redirect
    header('Location: http://' . $_SERVER['HTTP_HOST']);
    exit;
  }

  public function getImages() {
    $images = [];
    $files = [];
    $imageDir = opendir(IMAGES_DIR);
    while (false !== ($file = readdir($imageDir))) {
      if ($file === '.' || $file === '..') {
        continue;
      }
      $files[] = $file;
      if (file_exists(THUMBNAIL_DIR . '/' . $file)) {
        $images[] = basename(THUMBNAIL_DIR) . '/' . $file;
      } else {
        $images[] = basename(IMAGES_DIR) . '/' . $file;
      }
    }
    array_multisort($files, SORT_DESC, $images);
    return $images;
  }

  private function _createThumbnail($savePath) {
    $imageSize = getimagesize($savePath);
    $width = $imageSize[0];
    $height = $imageSize[1];
    if ($width > THUMBNAIL_WIDTH) {
      $this->_createThumbnailMain($savePath, $width, $height);
    }
  }

  private function _createThumbnailMain($savePath, $width, $height) {
    switch($this->_imageType) {
      case IMAGETYPE_GIF:
        $srcImage = imagecreatefromgif($savePath);
        break;
      case IMAGETYPE_JPEG:
        $srcImage = imagecreatefromjpeg($savePath);
        break;
      case IMAGETYPE_PNG:
        $srcImage = imagecreatefrompng($savePath);
        break;
    }
    $thumbHeight = round($height * THUMBNAIL_WIDTH / $width);
    $thumbImage = imagecreatetruecolor(THUMBNAIL_WIDTH, $thumbHeight);
    imagecopyresampled($thumbImage, $srcImage, 0, 0, 0, 0, THUMBNAIL_WIDTH, $thumbHeight, $width, $height);

    switch($this->_imageType) {
      case IMAGETYPE_GIF:
        imagegif($thumbImage, THUMBNAIL_DIR . '/' . $this->_imageFileName);
        break;
      case IMAGETYPE_JPEG:
        imagejpeg($thumbImage, THUMBNAIL_DIR . '/' . $this->_imageFileName);
        break;
      case IMAGETYPE_PNG:
        imagepng($thumbImage, THUMBNAIL_DIR . '/' . $this->_imageFileName);
        break;
    }

  }

  private function _save($ext) {
    $this->_imageFileName = sprintf(
      '%s_%s.%s',
      time(),
      sha1(uniqid(mt_rand(), true)),
      $ext
    );
    $savePath = IMAGES_DIR . '/' . $this->_imageFileName;
    $res = move_uploaded_file($_FILES['image']['tmp_name'], $savePath);
    if ($res === false) {
      throw new \Exception('Could not upload!');
    }
    return $savePath;
  }

  private function _validateImageType() {
    $this->_imageType = exif_imagetype($_FILES['image']['tmp_name']);
    switch($this->_imageType) {
      case IMAGETYPE_GIF:
        return 'gif';
      case IMAGETYPE_JPEG:
        return 'jpg';
      case IMAGETYPE_PNG:
        return 'png';
      default:
        throw new \Exception('PNG/JPEG/GIF only!');
    }
  }

  private function _validateUpload() {
    // var_dump($_FILES);
    // exit;

    if (!isset($_FILES['image']) || !isset($_FILES['image']['error'])) {
      throw new \Exception('Upload Error!');
    }

    switch($_FILES['image']['error']) {
      case UPLOAD_ERR_OK:
        return true;
      case UPLOAD_ERR_INI_SIZE:
      case UPLOAD_ERR_FORM_SIZE:
        throw new \Exception('File too large!');
      default:
        throw new \Exception('Err: ' . $_FILES['image']['error']);
    }

  }
}

はじめてのVBA その4

VBAではIf分も書ける。

Sub IfTest()

    If Range("a1").Value > 80 Then
        Range("a2").Value = "OK!"
    ElseIf Range("a1").Value > 60 Then
        Range("a2").Value = "soso..."
    Else
        Range("a2").Value = "NG!"
    End If


End Sub

VBAではCase文だって書ける。

Sub SelectTest()

    Dim signal As String
    signal = Range("a1").Value
    
    Dim result As Range
    Set result = Range("a2")
    
    Select Case signal
    
    Case "red"
        result.Value = "STOP!"
        
    Case "green"
        result.Value = "GO!"
    
    Case "yellow"
        result.Value = "CAUTION!"
        
    Case Else
        result.Value = "n.a."
        
    End Select
    

End Sub

VBAではWhile分だって。

Sub WhileTest()
    Dim i As Integer
    i = 1
    
    Do While i < 10
        Cells(i, 1).Value = i
        i = i + 1
    Loop

End Sub
Sub ForTest()
    Dim i As Integer
    
    For i = 1 To 9 Step 2
        Cells(i, 1).Value = i
    Next i

End Sub

基本的なif、ループ系に関しても全然使える。 書き方だけは各々特徴がある感じだけども。

はじめてのVBA その3

vbaで変数を使う場合。 宣言の仕方は「Dim」と書いた後に変数名を書。 その後に、その変数につけるデータは何型かを指定する必要があり。 ちなみに下のコードに書いてあるIntegerに関しては整数型。 他の形は以下参照。

Sub VariableTest()

    Dim x As Integer
    
    x = 10 + 5
    x = x + 1
    
    ' + - / *
    ' \ mod ^
    
    x = 2 ^ 3
    
    ' Range("A1").Value = x
    Debug.Print x

End Sub

デバックの方式としては「Debug.Print」こちらの形で中身を確認できる。 xの値をイミディエイトウィンドウに表示することができる。 オブジェクト型は他のデータ型と違って、 セットする時に必ず「Set」をつけるので忘れないようにする。

Attribute VB_Name = "Module1"
Sub VariableTest()

    Dim y As Double ' 実数
    Dim s As String ' 文字
    Dim d As Date ' 日付
    Dim z As Variant ' 入ってた時に決める
    Dim f As Boolean ' 真偽値
    Dim r As Range ' 実数
    
    y = 10.5
    s = "hello"
    d = "2012/04/23"
    f = True
    Set r = Range("A1")
    
    Debug.Print y / 3
    Debug.Print s & "world"
    r.Value = d + 7

End Sub

配列の形としては以下二つの書き方があり。

Sub VariableTest()

    Dim sales(2) As Integer
    sales(0) = 200
    sales(1) = 150
    sales(2) = 300
    
    Debug.Print sales(1)

End Sub
Sub VariableTest2()
    Dim sales As Variant
    sales = Array(200, 150, 300)
    Debug.Print sales(2)

End Sub

はじめてのVBA その2

ある特定の対象に対して、複数の操作をしたい時(プロパティを変えるなど)に、 まとめて書くやり方withを使う方法がある。
withTestはそれぞれ一つづつ書いた場合。
WithTest2はwithを使ってまとめた場合。

Sub WithTest()
    Range("A1").Value = "hello"
    Range("A1").Font.Bold = True
    Range("A1").Font.Size = 16
    Range("A1").Interior.Color = vbRed
End Sub
Sub WithTest2()
    With Range("A2")
        .Value = "hello"
        With .Font
            .Bold = True
            .Size = 16
        End With
        .Interior.Color = vbRed
    End With
End Sub

セルの値を取得する場合。 ValueかFont.Sizeで値や文字サイズを取得可能。

Sub GetTest()
    MsgBox (Range("A1").Value)
    MsgBox (Range("A1").Font.Size)
End Sub

メソッド名を書くと何らかの処理が行われる。

Sub MethodTest()
    ' Range("B2").Clear
    ' Range("B5").Delete shift:=xlShiftUp
    Worksheets.Add after:=Worksheets("Sheet2"), Count:=2 ' 
End Sub

2行目はセルの中身削除。
3行目はセルのB5を削除して上に詰める。
4行目はシート2から二つシートを追加。