20200705のPHPに関する記事は14件です。

出来るだけ最小限でdocker-compose、nginx、phpの環境を作成してみた

私は初心者です。間違っていたりもっと良いやり方がありましたら教えていただけるとありがたいです

参考

こちらのリンクにコードを置きました

docker-compose.yml
version: "3"

services:
  web:
    image: nginx
    ports:
      - "8080:80"
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf
      - ./myapp:/var/www/html
    depends_on:
      - php

  php:
    image: php:7-fpm
    volumes:
      - ./myapp:/var/www/html

phpのサービスだけで、/var/www/html にファイルをマウントしたら良いかと思ったのですが、htmlが表示されず(ファイルがなくて404になる)webのサービスの方でも/var/www/htmlマウントしました

default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
    root /var/www/html;

    location / {
        index  index.php index.html;
    }

    location ~ \.php$ {
       fastcgi_pass   php:9000;
       fastcgi_index  index.php;
       fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
       include        fastcgi_params;
    }
}
myapp/index.php
<?php
phpinfo();
docker compose up -d

image.png

以上です。m(_ _)m

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

wordpressにadvancedCustomFieldを使って絞り込み機能付きリクルートページを実装してみる

ポイント

1.カスタム投稿タイプ
2.アドバンスドカスタムフィールド
3.絞り込み機能

カスタム投稿タイプの追加

function.php
// カスタム投稿タイプの追加
add_action('init', 'create_post_type');
function create_post_type() {
  //カスタム投稿タイプ(ここから)
  register_post_type(
      'area',
      array(
          'labels' => array(
              'name' => __('リクルート'), // 表示する投稿タイプ名
              'singular_name' => __('リクルート')
          ),
          'public' => true,
          'menu_position' => 7,
          'supports' => array('title', 'editor', 'thumbnail'),
          'has_archive' => true,
      )
  );
}

Advanced Custom Fieldをインストール

image.png

プラグインをインストールして有効化してください。

カスタムフィールドの作成

項目を作成します。
image.png

記事の作成

リクルート情報を入力していきます。
image.png

ページを作成します。

一覧画面

※追加しても404になる場合はパーマリンクを更新してみてください。

archive-area.php
<?php
/**
 * The template for displaying archive pages
 *
 * @link https://codex.wordpress.org/Template_Hierarchy
 *
 * @package WordPress
 * @subpackage Twenty_Seventeen
 * @since 1.0
 * @version 1.0
 */

get_header(); ?>

<header class="entry-header">
  <h1 class="entry-title"> Recruit<span>募集要項一覧</span></h1>
</header>
<?php
// ?getarea=&getregion=&kinmu=&type=&time=&job=
$params = "&getregion=".$_GET['getregion']."&kinmu=".$_GET['kinmu']."&type=".$_GET['type']."&time=".$_GET['time']."&job=".$_GET['job'];

/**
 * getarea:募集エリア
 * getregion:拠点名
 */
if ($_REQUEST["getarea"] == "東北エリア" || $_REQUEST["getregion"] == "仙台") {
  $breadcrumbs1 = '<a href="?getarea=東北エリア">東北エリア</a>';
}
if ($_REQUEST["getarea"] == "関東エリア" || $_REQUEST["getregion"] == "東京" || $_REQUEST["getregion"] == "横浜") {
  $breadcrumbs1 = '<a href="?getarea=関東エリア">関東エリア</a>';
}
?>

<div id="topicpath"><a href="/">HOME</a> &gt; <a href="/area/">募集要項一覧</a> <?php echo $breadcrumbs1 ? " &gt; ".$breadcrumbs1 : ""; ?> <?php echo $_REQUEST["getregion"] ? " &gt; ".$_REQUEST["getregion"] : ""; ?></div><!-- /#topicpath -->

<?php
if (!$_REQUEST["getarea"] && !$_REQUEST["getregion"]) {
  ?>

  <div class="areaList">
    <div class="areaListInner">
      <div><a href="/area/?getarea=東北エリア<?php echo $params;?>" class="<?php getCountArea("東北エリア"); ?>">東北エリア</a></div>
      <div><a href="/area/?getarea=関東エリア<?php echo $params;?>" class="<?php getCountArea("関東エリア"); ?>">関東エリア</a></div>
    </div><!-- /.areaListInner -->
  </div><!-- /.areaList -->
  <?php
}
?>
<?php
// ?getarea=&getregion=&kinmu=&type=&time=&job=
$params = "&kinmu=".$_GET['kinmu']."&type=".$_GET['type']."&time=".$_GET['time']."&job=".$_GET['job'];


if ($_REQUEST["getarea"] == "東北エリア" || $_REQUEST["getregion"] == "仙台") {
  ?>
  <div class="areaList">
    <div class="areaListInner">
      <div><a href="/area/?getregion=仙台<?php echo $params;?>" class="<?php getCountKyoten("仙台"); ?>">宮城県<span>(仙台市)</span></a></div>
    </div><!-- /.areaListInner -->
  </div><!-- /.areaList -->
  <?php
}
?>
<?php
if ($_REQUEST["getarea"] == "関東エリア" || $_REQUEST["getregion"] == "東京" || $_REQUEST["getregion"] == "横浜") {
  ?>
  <div class="areaList">
    <div class="areaListInner">
      <div><a href="/area/?getregion=東京<?php echo $params;?>" class="<?php getCountKyoten("東京"); ?> <?php setActive("東京"); ?>">東京<span>(23区)</span></a></div>
      <div><a href="/area/?getregion=横浜<?php echo $params;?>" class="<?php getCountKyoten("横浜"); ?> <?php setActive("横浜"); ?>">神奈川県<span>(横浜市)</span></a></div>
    </div><!-- /.areaListInner -->
  </div><!-- /.areaList -->
  <?php
}
?>

<?php
$acf_args = array(
    'post_type' => 'area', //取得したい投稿タイプ
    'post_per_page' => 1, //とりあえず、1つだけ取得
);
$acf_posts = get_posts($acf_args);
$field_kinmu_arr = get_field_object('拠点名', $acf_posts->ID);
$field_type_arr = get_field_object('雇用形態', $acf_posts->ID);
$field_job_arr = get_field_object('職種別のみ', $acf_posts->ID);
$field_time_arr = get_field_object('勤務時間帯', $acf_posts->ID);
?>
<section>
  <h2>検索条件<span>Search</span></h2>
  <div class="row">
    <div class="col-md-10 col-md-offset-1">
      <div class="pulldownMenu">
        <ul>

          <input type="hidden"  id="submit_select1" value="<?php echo $_GET["kinmu"];?>">

          <li>
            <div class="select-wrap">
              <form id="submit_form1" method="get" action="#">
                <select name="type" id="submit_select2">
                  <option value="">雇用形態</option>
                  <?php
                  foreach ($field_type_arr["choices"] as $value => $label) {
                    if (!empty($_GET["type"]) && $_GET["type"] == $value) {
                      $selected = "selected";
                    } else {
                      $selected = "";
                    }
                    echo "<option value=\"{$value}\" $selected>{$label}</option>";
                  }
                  ?>
                </select>
              </form>
            </div>
          </li>
          <li>
            <div class="select-wrap">
              <form id="submit_form2" method="get" action="#">
                <select name="job" id="submit_select3">
                  <option value="">職種</option>
                  <?php
                  foreach ($field_job_arr["choices"] as $value => $label) {
                    if (!empty($_GET["job"]) && $_GET["job"] == $value) {
                      $selected = "selected";
                    } else {
                      $selected = "";
                    }
                    echo "<option value=\"{$value}\" $selected>{$label}</option>";
                  }
                  ?>
                </select>
              </form>
            </div>
          </li>

          <input type="hidden"  id="submit_select3" value="<?php echo $_GET["job"];?>">

        </ul>
      </div>
      <?php
      /**
       * 各種絞り込み
       */
      $meta_array = array();
      if ($_REQUEST["kinmu"]) {
        $meta_array[] = array(
            'key' => '拠点名',
            'value' => $_REQUEST["kinmu"],
            'compare' => '=',
        );
      }
      if ($_REQUEST["type"]) {
        $meta_array[] = array(
            'key' => '雇用形態',
            'value' => $_REQUEST["type"],
            'compare' => '=',
        );
      }
      if ($_REQUEST["job"]) {
        $meta_array[] = array(
            'key' => '職種別のみ',
            'value' => $_REQUEST["job"],
            'compare' => '=',
        );
      }
      if ($_REQUEST["time"]) {
        $meta_array[] = array(
            'key' => '勤務時間帯',
            'value' => $_REQUEST["time"],
            'compare' => '=',
        );
      }
      if ($_REQUEST["getarea"]) {
        $meta_array[] = array(
            'key' => '募集エリア',
            'value' => $_REQUEST["getarea"],
            'compare' => '=',
        );
      }
      if ($_REQUEST["getregion"]) {
        $meta_array[] = array(
            'key' => '拠点名',
            'value' => $_REQUEST["getregion"],
            'compare' => '=',
        );
      }

      $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
      $args = array(
          'posts_per_page' => 10,
          'post_type' => 'area',
          'orderby' => 'modified',
          'order' => 'desc',
          'post_status' => 'publish',
          'meta_query' => array(
              $meta_array,
              'relation' => 'AND'
          ),
          'paged' => $paged,
      );

//      echo count($args);

      $my_query = new WP_Query($args);
      // 件数表示
      if ($my_query->found_posts > 0) {
        echo "<p class=\"text-right\">検索結果:<span class=\"lead\">".$my_query->found_posts."</span>件</p>";
      }


      if ($my_query->have_posts()) : ?>
        <?php
        /* Start the Loop */
        while ($my_query->have_posts()) : $my_query->the_post();

          ?>
          <div class="post_item">
          <h3><?php echo get_field('募集要項タイトル') ? get_field('募集要項タイトル') : "no title"; ?></h3>
          <?php
          $new = "";
//          $day1 = strtotime(the_date('Y-m-d', '', '', false));
          $day1 = strtotime(the_modified_date('Y-m-d', '', '', false));
          $day2 = strtotime(date('Y-m-d'));
          $sa = ($day2 - $day1) / (60 * 60 * 24). '日';
          // 投稿日が新着マーク表示日数以内ならNEWマーク出す:新着マーク表示日数
          $hyoji_nissuu = get_field('新着マーク表示日数') ? get_field('新着マーク表示日数') : 7;
          if($sa < $hyoji_nissuu) $new = "NEW!";
          ?>
          <p class="tag">
<!--            <span class="label label-default">--><?php //echo get_field('募集エリア') ? get_field('募集エリア') : ""; ?><!--</span>-->
            <span class="label label-default"><?php echo get_field('雇用形態') ? get_field('雇用形態') : ""; ?></span>
            <span class="label label-default"><?php echo get_field('職種別のみ') ? get_field('職種別のみ') : ""; ?></span>
            <span class="label label-default"><?php echo get_field('勤務時間帯') ? get_field('勤務時間帯') : ""; ?></span></p>
          <span class="new_mark"><?php echo $new; ?></span>
          <table class="outline-table table">
            <tr>
              <th>職種</th>
              <td><?php echo get_field('職種') ? get_field('職種') : ""; ?></td>
            </tr>
            <tr>
              <th>募集拠点</th>
              <td><?php echo get_field('募集エリア') ? get_field('募集エリア') : ""; ?> <?php getShi(get_field('拠点名')); ?></td>
            </tr>
            <tr>
              <th>勤務地住所</th>
              <td><?php echo get_field('勤務地住所') ? get_field('勤務地住所') : ""; ?></td>
            </tr>
            <tr>
              <th>雇用形態</th>
              <td><?php echo get_field('雇用形態') ? get_field('雇用形態') : ""; ?></td>
            </tr>
            <tr>
              <th>勤務時間</th>
              <td><?php echo get_field('勤務時間帯st') ? get_field('勤務時間帯st') : ""; ?><?php echo get_field('勤務時間帯ed') ? get_field('勤務時間帯ed') : ""; ?></td>
            </tr>
            <tr>
              <th>給与</th>
              <td><?php echo get_field('給与種類') ? get_field('給与種類') : ""; ?> <?php echo get_field('給与範囲下') ? get_field('給与範囲下')."円" : ""; ?><?php echo get_field('給与範囲上') ? get_field('給与範囲上')."円" : ""; ?></td>
            </tr>
            <tr>
              <th>休日・休暇</th>
              <td><?php echo get_field('休日') ? implode('/', get_field('休日')) : ""; ?>  <?php echo get_field('休暇') ? implode('/', get_field('休暇')) : ""; ?></td>
            </tr>
            <tr>
              <th>受付担当者</th>
              <td><?php echo get_field('採用受付担当者') ? get_field('採用受付担当者') : ""; ?></td>
            </tr>
          </table>
          <div class="row">
            <div class="col-sm-12"><a href="<?php the_permalink() ?>" class="btn recruit_more">詳細情報を見る</a></div>
          </div>
          </div>
        <?php
        endwhile;

      else :
        get_template_part('template-parts/post/content', 'none');
      endif; ?>
    </div>
  </div>
</section>
<div class="pagenavi">
  <p class="btn">
    <?php
    $big = 999999999; // need an unlikely integer

    echo paginate_links(array(
        'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))),
        'format' => '?paged=%#%',
        'current' => max(1, get_query_var('paged')),
        'total' => $my_query->max_num_pages
    ));
    ?>
  </p>
</div>
<?php get_footer(); ?>
<script>
  $(function () {
    var curURL = document.URL
    var arg = new Object
    var pair = location.search.substring(1).split('&')
    for (var i = 0; pair[i]; i++) {
      var kv = pair[i].split('=')
      arg[kv[0]] = kv[1]
    }
    console.log(arg)
    $('[id^=submit_select]').change(function () {
      var getarea = arg.getarea === undefined ? '' : arg.getarea
      var getregion = arg.getregion === undefined ? '' : arg.getregion
      location.href = '/area/?getarea=' + getarea + '&getregion=' + getregion + '&kinmu=' + $('#submit_select1').val() + '&type=' + $('#submit_select2').val() + '&time=' + $('#submit_select4').val() + '&job=' + $('#submit_select3').val()
    })
  })
</script> 

記事画面

※追加しても404になる場合はパーマリンクを更新してみてください。

single-area.php
<?php
/**
 * Template part for displaying page content in page.php.
 *
 * @link https://codex.wordpress.org/Template_Hierarchy
 *
 * @package
 */
?>
<style>
  h3 {
    padding-left: 30px;
    background-image:url(/recruit/wp-content/themes/under-material-master/img/h3.png);
  }
</style>
<hr class="sp" style="border-top: 2px solid #000;">
<h1 class="entry-title pc">Details<span>募集要項詳細</span></h1>
<div id="topicpath"><a href="/recruit/">HOME</a> &gt; <a href="/recruit/area/">募集要項一覧</a> &gt;
  <a href="/recruit/area/?getarea=<?php echo get_field('募集エリア') ? get_field('募集エリア') : ""; ?>"><?php echo get_field('募集エリア') ? get_field('募集エリア') : ""; ?></a> >
    <a href="/recruit/area/?getregion=<?php echo get_field('拠点名') ? get_field('拠点名') : ""; ?>"><?php getShi(get_field('拠点名')); ?></a> >
  <?php echo get_field('求人コード') ? get_field('求人コード') : ""; ?>-<?php echo get_field('求人コードNo') ? get_field('求人コードNo') : ""; ?></div>
<!-- /#topicpath -->
<section>
  <div class="heading">
    <h2><?php echo get_field('募集要項タイトル') ? get_field('募集要項タイトル') : "no title"; ?></h2>
  </div>
  <h3><?php getShi(get_field('拠点名')); ?></h3>
  <div class="row">
    <div class="col-md-10 col-md-offset-1">
      <div class="yokoIco">
        <ul class="tag list-inline">
          <li class="keitai list-inline-item">
            <p class="label label-default"><?php echo get_field('雇用形態') ? get_field('雇用形態') : ""; ?></p>
          </li>
          <li class="keitai list-inline-item">
            <p class="label label-default"><?php echo get_field('職種別のみ') ? get_field('職種別のみ') : ""; ?></p>
          </li>
          <li class="hours list-inline-item">
            <p class="label label-default"><?php echo get_field('勤務時間帯') ? get_field('勤務時間帯') : ""; ?></p>
          </li>
        </ul>
      </div>
      <!-- /.yokoIco -->
      <!-- 修正・追加 2018-04-08 ここまで -->

      <div class="areaDetail">
        <div class="areaDetailInner row">
          <div class="col-xs-6">
            <?php
            if (get_field('拠点紹介画像1')): ?>
              <img src="<?php the_field('拠点紹介画像1'); ?>"/>
            <?php else: ?>
              <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
            <?php endif; ?>
          </div>
          <div class="col-xs-6">
            <?php
            if (get_field('拠点紹介画像2')): ?>
              <img src="<?php the_field('拠点紹介画像2'); ?>"/>
            <?php else: ?>
              <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
            <?php endif; ?>
          </div>
        </div>
        <!-- /.areaDetailInner -->
      </div>
      <!-- /.areaDetail -->
        <div class="leader">
          <?php
          if (get_field('拠点長画像')): ?>
            <img src="<?php the_field('拠点長画像'); ?>"/>
          <?php else: ?>
            <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
          <?php endif; ?>
        <div class="introduction"><p><?php echo get_field('拠点紹介文') ? get_field('拠点紹介文') : ""; ?></p></div>
        <!-- /.introduction -->
</div>
      <div style="clear: both;"></div>
      <h3>職場の雰囲気</h3>

      <div class="threeCol pc_view">
        <div class="threeColInner row horizontal_scroll">
          <div class="photoText">
            <?php
            if (get_field('職場の雰囲気画像1')): ?>
              <img src="<?php the_field('職場の雰囲気画像1'); ?>"/>
            <?php endif; ?>
            <p>
              <?php echo get_field('職場の雰囲気1場面説明') ? get_field('職場の雰囲気1場面説明') : ""; ?>
            </p>
          </div><!-- /.photoText -->

          <div class="photoText">
            <?php
            if (get_field('職場の雰囲気画像2')): ?>
              <img src="<?php the_field('職場の雰囲気画像2'); ?>"/>
            <?php endif; ?>
            <p>
              <?php echo get_field('職場の雰囲気2場面説明') ? get_field('職場の雰囲気2場面説明') : ""; ?>
            </p>
          </div><!-- /.photoText -->

          <div class="photoText">
            <?php
            if (get_field('職場の雰囲気画像3')): ?>
              <img src="<?php the_field('職場の雰囲気画像3'); ?>"/>
            <?php endif; ?>
            <p>
              <?php echo get_field('職場の雰囲気3場面説明') ? get_field('職場の雰囲気3場面説明') : ""; ?>
            </p>
          </div><!-- /.photoText -->
        </div><!-- /.threeColInner -->
      </div><!-- /.threeCol -->

      <!-- Slider main container -->
      <div class="swiper-container mb60 sp_view">
        <!-- Additional required wrapper -->
        <div class="swiper-wrapper">
          <!-- Slides -->
          <?php
          if (get_field('職場の雰囲気画像1')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('職場の雰囲気画像1'); ?>"/>
              <p>
                <?php echo get_field('職場の雰囲気1場面説明') ? get_field('職場の雰囲気1場面説明') : ""; ?>
              </p>
            </div>
          <?php endif; ?>

          <?php
          if (get_field('職場の雰囲気画像2')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('職場の雰囲気画像2'); ?>"/>
              <p>
                <?php echo get_field('職場の雰囲気2場面説明') ? get_field('職場の雰囲気2場面説明') : ""; ?>
              </p>
            </div>
          <?php endif; ?>

          <?php
          if (get_field('職場の雰囲気画像3')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('職場の雰囲気画像3'); ?>"/>
              <p>
                <?php echo get_field('職場の雰囲気3場面説明') ? get_field('職場の雰囲気3場面説明') : ""; ?>
              </p>
            </div>
          <?php endif; ?>

        </div>
        <div class="swiper-pagination"></div>

        <div class="swiper-button-prev">
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 27 44">
            <path class="arrow arrow-left" d="M0,22L22,0l2.1,2.1L4.2,22l19.9,19.9L22,44L0,22L0,22L0,22z"  />
          </svg>
        </div><!-- .swiper-button-prev -->

        <div class="swiper-button-next">
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 27 44">
            <path class="arrow arrow-right" d="M27,22L27,22L5,44l-2.1-2.1L22.8,22L2.9,2.1L5,0L27,22L27,22z" />
          </svg>
        </div><!-- .swiper-button-next -->
      </div>

      <!-- /.slide -->

      <h3>仕事の特徴</h3>
      <div class="threeCol pc_view">
        <div class="threeColInner row horizontal_scroll">
          <div class="photoText col-sm-4">
            <?php
            if (get_field('仕事の特徴画像1')): ?>
              <img src="<?php the_field('仕事の特徴画像1'); ?>"/>
            <?php else: ?>
              <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
            <?php endif; ?>
          </div>
          <!-- /.photoText -->
          <div class="photoText col-sm-4">
            <?php
            if (get_field('仕事の特徴画像2')): ?>
              <img src="<?php the_field('仕事の特徴画像2'); ?>"/>
            <?php else: ?>
              <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
            <?php endif; ?>
          </div>
          <!-- /.photoText -->
          <div class="photoText col-sm-4">
            <?php
            if (get_field('仕事の特徴画像3')): ?>
              <img src="<?php the_field('仕事の特徴画像3'); ?>"/>
            <?php else: ?>
              <img src="https://placehold.jp/32/006699/99bbdd/320x200.png?text=Now+printing"/>
            <?php endif; ?>
          </div>
          <!-- /.photoText -->
        </div>
        <!-- /.threeColInner -->
        <hr>
        <div class="photoText">
          <p> <?php echo get_field('仕事内容紹介文') ? get_field('仕事内容紹介文') : ""; ?> </p>
        </div>
        <!-- /.threeCol -->
      </div>
      <!-- /.threeCol -->
      <!-- Slider main container -->
      <div class="swiper-container mb60 sp_view">
        <!-- Additional required wrapper -->
        <div class="swiper-wrapper">
          <!-- Slides -->
          <?php
          if (get_field('仕事の特徴画像1')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('仕事の特徴画像1'); ?>"/>
            </div>
          <?php endif; ?>

          <?php
          if (get_field('仕事の特徴画像2')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('仕事の特徴画像2'); ?>"/>
            </div>
          <?php endif; ?>

          <?php
          if (get_field('仕事の特徴画像3')): ?>
            <div class="swiper-slide">
              <img src="<?php the_field('仕事の特徴画像3'); ?>"/>
            </div>
          <?php endif; ?>

        </div>
        <div class="swiper-pagination"></div>

        <div class="swiper-button-prev">
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 27 44">
            <path class="arrow arrow-left" d="M0,22L22,0l2.1,2.1L4.2,22l19.9,19.9L22,44L0,22L0,22L0,22z" />
          </svg>
        </div><!-- .swiper-button-prev -->

        <div class="swiper-button-next">
          <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 27 44">
            <path class="arrow arrow-right" d="M27,22L27,22L5,44l-2.1-2.1L22.8,22L2.9,2.1L5,0L27,22L27,22z" />
          </svg>
        </div><!-- .swiper-button-next -->
      </div>
      <!-- /.slide -->

      <div class="heading">
        <h3>募集要項</h3>
      </div>
      <div class="box3 mb20">
        <div class="areaJob">
          <p class="catch"><?php echo get_field('募集要項タイトル') ? get_field('募集要項タイトル') : ""; ?></p>
        </div>
        <!-- /.areaJob -->
        <table class="outline-table table">
          <tbody>
          <tr>
            <th>職種</th>
            <td><?php echo get_field('職種') ? get_field('職種') : ""; ?></td>
          </tr>
          <tr>
            <th>募集エリア</th>
            <td><?php echo get_field('募集エリア') ? get_field('募集エリア') : ""; ?></td>
          </tr>
          <tr>
            <th>求人コード</th>
            <td><?php echo get_field('求人コード') ? get_field('求人コード') : ""; ?>-<?php echo get_field('求人コードNo') ? get_field('求人コードNo') : ""; ?></td>
          </tr>
          <tr>
            <th>仕事内容</th>
            <td><?php echo get_field('仕事内容紹介文') ? get_field('仕事内容紹介文') : ""; ?>
            </td>
          </tr>
          <tr>
            <th>拠点名</th>
            <td><?php echo get_field('拠点名') ? get_field('拠点名') : ""; ?></td>
          </tr>
          <tr>
            <th>勤務地住所</th>
            <td><?php echo get_field('勤務地住所') ? get_field('勤務地住所') : ""; ?></td>
          </tr>
          <tr>
            <th>給与</th>
            <td><?php echo get_field('給与種類') ? get_field('給与種類') : ""; ?> <?php echo get_field('給与範囲下') ? get_field('給与範囲下')."円" : ""; ?><?php echo get_field('給与範囲上') ? get_field('給与範囲上')."円" : ""; ?></td>
          </tr>
          <?php
          if (get_field('年収例')){
          ?>
          <tr>
            <th>年収例</th>
            <td><?php echo get_field('年収例') ? get_field('年収例') : ""; ?></td>
          </tr>
          <?php
          }
          ?>
          <?php
          if (get_field('給与特記事項')){
          ?>
          <tr>
            <th>給与特記事項</th>
            <td><?php echo get_field('給与特記事項') ? get_field('給与特記事項') : ""; ?></td>
          </tr>
            <?php
          }
          ?>
          <?php
          if (get_field('交通費')){
          ?>
          <tr>
            <th>交通費</th>
            <td><?php echo get_field('交通費') ? get_field('交通費') : ""; ?></td>
          </tr>
            <?php
          }
          ?>
          <tr>
            <th>手当</th>
            <td><?php echo get_field('手当') ? implode('/', get_field('手当')) : ""; ?></td>
          </tr>
          <tr>
            <th>賃金の締め・支払い日</th>
            <td><?php echo get_field('賃金〆日支払日') ? get_field('賃金〆日支払日') : ""; ?></td>
          </tr>
          <tr>
            <th>雇用形態</th>
            <td><?php echo get_field('雇用形態') ? get_field('雇用形態') : ""; ?></td>
          </tr>
          <tr>
            <th>勤務時間(勤務体系)</th>
            <td><?php echo get_field('勤務時間帯st') ? get_field('勤務時間帯st') : ""; ?><?php echo get_field('勤務時間帯ed') ? get_field('勤務時間帯ed') : ""; ?></td>
          </tr>
          <?php
          if (get_field('勤務時間特記事項')){
          ?>
          <tr>
            <th>勤務時間特記事項</th>
            <td><?php echo get_field('勤務時間特記事項') ? get_field('勤務時間特記事項') : ""; ?></td>
          </tr>
            <?php
          }
          ?>
          <tr>
            <th>待遇・福利厚生</th>
            <td><?php echo get_field('待遇・福利厚生') ? implode('/', get_field('待遇・福利厚生')) : ""; ?><?php echo get_field('待遇・福利厚生特記事項') ? get_field('待遇・福利厚生特記事項') : ""; ?></td>
          </tr>
          <tr>
            <th>加入保険</th>
            <td><?php echo get_field('加入保険') ? implode('/', get_field('加入保険')) : ""; ?></td>
          </tr>
          <tr>
            <th>休日・休暇</th>
            <td><?php echo get_field('休日') ? implode('/', get_field('休日')) : ""; ?><br>

              <?php echo get_field('休暇') ? implode('/', get_field('休暇')) : ""; ?><br>
              <?php echo get_field('休日・休暇特記事項') ? get_field('休日・休暇特記事項') : ""; ?>
            </td>
          </tr>
          <tr>
            <th>必要資格・免許等</th>
            <td><?php echo get_field('必要資格・免許') ? implode('/', get_field('必要資格・免許')) : ""; ?>
              <p><?php echo get_field('必要資格・免許特記事項') ? get_field('必要資格・免許特記事項') : ""; ?></p></td>
          </tr>
          <tr>
            <th>採用プロセス</th>
            <td><?php echo get_field('採用プロセス') ? get_field('採用プロセス') : ""; ?></td>
          </tr>
          <tr>
            <th>採用受付担当者</th>
            <td><?php echo get_field('採用受付担当者') ? get_field('採用受付担当者') : ""; ?></td>
          </tr>
          </tbody>
        </table>
      </div>
      <span style="color: white;font-size: 0px;">ハローワーク、未経験歓迎、未経験者、フリーター、シニア、主婦、主夫、20代、30代、40代、50代、新卒、第二新卒、中高年、バスドライバー、バス運転手、タクシードライバー、タクシー運転手、送迎ドライバー、回送ドライバー、普通免許、中型免許、準中型免許、大型免許、フォークリフト免許、運送会社、ロジスティック、物流、運送、輸送、倉庫、倉庫作業、トレーラードライバー、大型ドライバー、大型トラック運転手、中型ドライバー、中型トラック運転手、小型トラック、軽自動車ドライバー、平ボディ、バンボディ、保冷車、冷凍冷蔵車、ウィングボディ、ウィング車、幌ウィング、2tトラック、2トン、3tトラック、3トン、3.5tトラック、3.5トン、4tトラック、4トン、5tトラック、5トン、10tトラック、10トン、近距離、地場、中距離、長距離</span>

      <!-- /.box3 -->
  <div class="heading">
    <h2>応募フォーム</h2>
  </div>
  <p class="text-center sp_text_l">下記入力欄に必須事項をご記入の上、確認画面に進むボタンを押して下さい。<br>
  お送り頂きました個人情報は厳重な管理の上取り扱います。<br>
  採用審査目的以外には一切使用致しません。</p>
  <section class="contact_form">
    <div class="row">
      <div class="col-md-8 col-md-offset-2">
        <div class="form">
          <img src="/recruit/wp-content/themes/under-material-master/img/step_1.png" alt="フォーム入力">
          <form method="post" action="/recruit/area_job-offer_form/postmail.cgi" class="contact">
            <table class="contact_sp">
              <tbody>
              <tr>
                <th>求人コード</th>
                <td><input type="text" name="code" value="<?php echo get_field('求人コード') ? get_field('求人コード') : ""; ?>-<?php echo get_field('求人コードNo') ? get_field('求人コードNo') : ""; ?>" readonly></td>
              </tr>
              <tr>
                <th>お名前 <span class="required">必須</span></th>
                <td><input type="text" name="_name" id="name" placeholder="山田 太郎"></td>
              </tr>
              <tr>
                <th>フリガナ <span class="required">必須</span></th>
                <td><input type="text" name="_name2" id="name2" placeholder="ヤマダ タロウ"></td>
              </tr>
              <tr>
                <th>生年月日</th>
                <td>
                  <input type="number" class="birth1" style="width:80px;float: left;"> <span style="width:20px;float: left;line-height: 32px;"></span>
                  <input type="number" class="birth2" style="width:70px;float: left;"> <span style="width:20px;float: left;line-height: 32px;"></span>
                  <input type="number" class="birth3" style="width:70px;float: left;"> <span style="width:20px;float: left;line-height: 32px;"></span>
                  <input type="hidden" name="_birth" value="" id="birth">
                </td>
              </tr>
              <tr>
                <th>住所</th>
                <td><input type="text" name="address" id="address" placeholder="東京都千代田区">
              </tr>
              <tr>
                <th>お電話番号 <span class="required">必須</span></th>
                <td>半角数字、固定・携帯どちらも可
                    <input type="tel" class="tel1" style="width:80px;float: left;"> <span style="width:10px;float: left;line-height: 32px;"> - </span>
                    <input type="tel" class="tel2" style="width:90px;float: left;"> <span style="width:10px;float: left;line-height: 32px;"> - </span>
                    <input type="tel" class="tel3" style="width:90px;float: left;">
                    <input type="hidden" name="_tel" value="" id="tel">
                </td>
              </tr>
              <tr>
                <th>メールアドレス <span class="required">必須</span></th>
                <td><input type="text" name="_email" id="email" placeholder="xxxxx@abcde.com(半角)"></td>
              </tr>
              <tr>
                <th>備考(要望・質問など)</th>
                <td><textarea rows="5" name="message" id="message"></textarea>
                  <input type="hidden" name="url" id="url" value="<?php echo (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; ?>" readonly>
                </td>
              </tr>
              </tbody>
            </table>
            <p class="button">
              <input id="submit_button" type="submit" value="確認画面に進む">
            </p>
          </form>
        </div>
      </div>

      <div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
        <script>
            $('[class^=tel]').blur(function () {
              var tel1 = $('.tel1').val()
              var tel2 = $('.tel2').val()
              var tel3 = $('.tel3').val()
              $('#tel').val(tel1 + '-' + tel2 + '-' + tel3)
              console.log(tel1 + '-' + tel2 + '-' + tel3)
            })

            $(document).ready(function () {
              var tel1 = $('.tel1').val()
              var tel2 = $('.tel2').val()
              var tel3 = $('.tel3').val()
              $('#tel').val(tel1 + '-' + tel2 + '-' + tel3)
            })
        </script>

        <script>
          $('[class^=birth]').blur(function () {
            var birth1 = $('.birth1').val()
            var birth2 = $('.birth2').val()
            var birth3 = $('.birth3').val()
            $('#birth').val(birth1 + '' + birth2 + '' + birth3 + '')
            console.log(birth1 + '' + birth2 + '' + birth3 + '')
          })

          $(document).ready(function () {
            var birth1 = $('.birth1').val()
            var birth2 = $('.birth2').val()
            var birth3 = $('.birth3').val()
            $('#birth').val(birth1 + '' + birth2 + '' + birth3 + '')
          })
        </script>
      </div>

    </div>
  </section>
  <!-- /.form -->
</section>

ひとまず表示できるようになりました

https://ドメイン/area/

で一覧が表示できるようになっていると思います。
上のプログラムコピペで動くと思うけど、おかしいところが多々あるのでメンテして行ければと思う。
解説も入れていきたい。

あとはここから応募もできるんですが、postmail使っているんですよね。
mwwpでできないかを試行錯誤する予定。
一番しんどいのはCSSです・・・

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 7 Captcha Tutorial – Create Captcha in PHP Contact Form

Learn how to create a PHP Captcha Script using the GD library with basic captcha validation to protect bot generated mails or spam.

click here to read more:

https://www.positronx.io/create-captcha-in-php-contact-form/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

How to Get Selected Values from Select Option in PHP 7

get single and multiple selected values from the select option or select dropdown list in PHP 7. We will also learn to add custom styling in select dropdown using HTML and CSS.

click here to read more:
https://www.positronx.io/how-to-get-selected-values-from-select-option-in-php/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プチ・スケジュール管理システム作ってみた

こんにちは、還暦女子です。

今度はスケジュール管理表を作ってみました。
お店や病院などの営業予定や出勤表、シフト表、マイスケジュール等CSSを工夫すれば色々使えるかなと思って考えました。
初めての試みがいっぱいで穴だらけのコードですが、とりあえず一通り動きました。

作りたい仕様

  • ログイン管理内で編集、別ページのプレビューで表示
  • HTMLで入力可
  • 祝日は自由にカスタマイズ
  • 毎月自動更新
  • データベースを使わないライトな作り

サイト設計とデザイン

plan.jpg

AdobeXDで作成しました。
サイトデザイン以外にも設定イメージ、マニュアル、プロトタイプでプレゼンテーションも使える便利マルチツールです。書き出しは画像形式以外にもプラグインを使えばPDFも可能です。

デザインを元にHTMLとCSSのテンプレートを作成します。
今回は水色ベース。

管理画面イメージ
write.jpg

プレビュー画面イメージ
prev.jpg

カレンダー管理画面

ログインすると当月の管理画面に移行します。
tableとname属性もphpのfor文で書き出し。
Postで変数に変換するのもfor文。プログラムって一つ一つ書かなくていいから便利です。
カレンダー部分はネットに載ってるものを拾ってきてカスタマイズしました。

更新するとfile_put_contents()でjsonファイルに上書きします。
ファイル名は変数を入れてdays'.$m.'.jsonとして常に当月のjsonを取得。
jsonは1月から12月の12個のファイルを作っておき、毎年このデータを使い回す予定です。
ログインとログアウトのページは省略します。

当月のカレンダー

control.php
<?php
//当月のカレンダー
    session_start();
    session_regenerate_id(true);
    if(isset($_SESSION['login']) === false){
        echo 'ログインしていません。';
        exit();
    }

    //XSS
    function html_esc($word){
        return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
    }

    //トークン生成
    function getCSRFToken()
    {
        $nonce = base64_encode(openssl_random_pseudo_bytes(48));
        setcookie('XSRF-TOKEN', $nonce);
        return $nonce;
    }
    $token = getCSRFToken();
    $token = html_esc($token);


    date_default_timezone_set('Asia/Tokyo'); //東京時間にする
    $y = date('Y');
    $m = date('m')+0;//+intをつけないと祝日設定できない
    $week = ['日','月','火','水','木','金','土'];
    //月末の日を取得
    $lastday = date("t", mktime(0, 0, 0, $m , 1 , $y));

    //json更新
    require_once(dirname(__FILE__).'/timer.php');
    //ファイル名は月で変動
    $file = file_get_contents('./json/days'.$m.'.json');                                     $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
    $array = json_decode($data,true);  


    if($_SERVER['REQUEST_METHOD'] === 'POST'){
        //postトークン追加
        function validateCSRFToken ($post_token)
        {
            return isset($_COOKIE['XSRF-TOKEN']) && $_COOKIE['XSRF-TOKEN'] === $post_token;
        }
        if(isset($_POST['csrf_token']) && validateCSRFToken($_POST['csrf_token'])){
            //OKだったら空文字でスルー
            echo '';
        } else {
            echo 'トークンが不正です。';
            exit();
        }    
        //パスをサーバーと合わせておく
        header('Access-Control-Allow-Origin: ファイルパス');
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('X-Frame-Options: SAMEORIGIN');
        //postトークンここまで

        //name値をfor文で書き出し
        for($i = 0; $i < $lastday; $i++){
            $name[$i] = html_esc($_POST['name'.$i]);
        }

        //JSON形式に変換 
        $json = json_encode($name);
        //JSON書き出し
        //タイマー設定が作用するので前月にもデータを入れておかないと消えてしまう
        file_put_contents('./json/days'.($m-1).'.json',$json);
        file_put_contents('./json/days'.$m.'.json',$json);
        //jsonファイルを取得、valueに再代入
        $file = file_get_contents('./json/days'.$m.'.json');
        //文字コードをUTF-8に変換する
        $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
        $array = json_decode($data,true);
    }

?>
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>スケジュールカレンダー管理画面 | 当月</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="format-detection" content="telephone=no">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="common/reset.css">
    <link rel="stylesheet" href="common/style.css">
    <!--ファビコン32x32-->
    <link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon">
</head>
<body>
<div id="wrapper">
   <header id="logout" class="clearfix"><a href="logout.php">ログアウト</a></header>
   <main>
     <h1 id="title">Myカレンダー管理画面</h1>
     <div id="infoLeft">
        <div>
            <p id="ym"><?php echo $y; ?><span><?php echo $m; ?></span></p>
            <p id="next"><a href="control2.php">翌月<span class="material-icons md-24">keyboard_arrow_right</span></a></p>
            <p id="view"><a target="_blank" rel="noopener" href="schedule.php">プレビュー</a></p>
        </div>
        <p id="info">HTMLも入力できます。<br>リンクや画像も貼ってカスタマイズができます。入力後更新ボタンを押すと表示用のページに自動入力されます。変更の場合は上書きしてください。</p>
     </div>
     <form action="" method="post">
     <!-- トークンの値をvalueに -->
     <input type="hidden" name="csrf_token" value="<?php echo $token ?>">
     <table id="cale">
        <tr><?php
                foreach($week as $weeks){
                    echo '<td>'.$weeks.'</td>';
                }            
            ?>
        </tr>
        <?php
      // 1日の曜日を取得
            $wd1 = date("w", mktime(0, 0, 0, $m, 1, $y));
            // その数だけ空白を表示
            for ($i = 1; $i <= $wd1; $i++) {
            echo "<td> </td>";
            }

            // 1日から月末日までの表示
            $d = 1;
            $n = 0;

            //休日を共通にしたかったので別ファイルに
            require_once(dirname(__FILE__).'/holiday.php');
            //holiday.phpで祝日設定
            for($d = 1; $d <= $lastday; $d++) {
                echo '<td class="'.$holiday[$d].'"><span class="days">'.$d.'</span><textarea class="memo" name="name'.$n.'" value="'.$array[$n].'">'.$array[$n].'</textarea></td>';
                // 今日が土曜日の場合は…
                if (date("w", mktime(0, 0, 0, $m, $d, $y)) == 6) {
                    // 週を終了
                    echo "</tr>";
                    // 次の週がある場合は新たな行を準備
                    if (checkdate($m, $d + 1, $y)) {
                        echo "<tr>";
                    }
                }
                $n++;
            } 

            // 最後の週の土曜日まで移動
            $wdx = date("w", mktime(0, 0, 0, $m + 1, 0, $y));
            for ($i = 1; $i < 7 - $wdx; $i++) {
            echo "<td> </td>";
            }
        ?>
     </table>
     <p id="update"><input type="submit" value="更新する"></p>
     </form>
   </main>
   <footer>
       <small>Copyright 2020 All Rights Reserved. 無断転載禁止</small>
   </footer>
</div>  
</body>
</html>

翌月のカレンダー

最初の月設定
$m = date('m')+1になってます。

control2.php
<?php
//翌月のカレンダー
    session_start();
    session_regenerate_id(true);
    if(isset($_SESSION['login']) === false){
        echo 'ログインしていません。';
        exit();
    }

    //XSS
    function html_esc($word){
        return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
    }

    //トークン生成
    function getCSRFToken()
    {
        $nonce = base64_encode(openssl_random_pseudo_bytes(48));
        setcookie('XSRF-TOKEN', $nonce);
        return $nonce;
    }
    $token = getCSRFToken();
    $token = html_esc($token);


    date_default_timezone_set('Asia/Tokyo'); //東京時間にする
    $y = date('Y');
    $m = date('m')+1;//+intをつけないと祝日設定できない
    $week = ['日','月','火','水','木','金','土'];
    //月末の日を取得
    $lastday = date("t", mktime(0, 0, 0, $m , 1 , $y));

    //jsonから翌月のデータ取得
    $file = file_get_contents('./json/days'.$m.'.json');                                     $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
    $array = json_decode($data,true);

    //次月に日付分の空文字設定jsonへ書き出し
    //年末だけ特別
    if($m === 12){
        $y = date('Y')+1;
        $days = [];
        for($i= 0; $i < date("t", mktime(0, 0, 0, 1 , 1 , $y)); $i++){
            $days[$i] = '';
        }
        $file = json_encode($days);
        file_put_contents('./json/days1.json',$file);
    } else {
        $days = [];
        for($i= 0; $i < date("t", mktime(0, 0, 0, ($m+1) , 1 , $y)); $i++){
            $days[$i] = '';
        }
        $file = json_encode($days);
        file_put_contents('./json/days'.($m+1).'.json',$file);
    }    

    if($_SERVER['REQUEST_METHOD'] === 'POST'){
        //postトークン追加
        function validateCSRFToken ($post_token)
        {
            return isset($_COOKIE['XSRF-TOKEN']) && $_COOKIE['XSRF-TOKEN'] === $post_token;
        }
        if(isset($_POST['csrf_token']) && validateCSRFToken($_POST['csrf_token'])){
            //OKだったら空文字でスルー
            echo '';
        } else {
            echo 'トークンが不正です。';
            exit();
        }    
        //パスをサーバーと合わせておく
        header('Access-Control-Allow-Origin: ファイルパス');
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('X-Frame-Options: SAMEORIGIN');
        //postトークンここまで

        //name値をfor文で書き出し
        for($i = 0; $i < $lastday; $i++){
            $name[$i] = html_esc($_POST['name'.$i]);
        }

        //JSON形式に変換 
        $json = json_encode($name);
        //JSON書き出し、パーミッション変更忘れずに
        file_put_contents('./json/days'.$m.'.json',$json);

        //jsonファイルを取得、valueに再代入
        $file = file_get_contents('./json/days'.$m.'.json');
        //文字コードをUTF-8に変換する
        $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
        $array = json_decode($data,true);

    }

?>
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>スケジュールカレンダー管理画面 | 翌月</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="format-detection" content="telephone=no">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="common/reset.css">
    <link rel="stylesheet" href="common/style.css">
    <!--ファビコン32x32-->
    <link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon">
</head>
<body>
<div id="wrapper">
   <header id="logout" class="clearfix"><a href="logout.php">ログアウト</a></header>
   <main>
     <h1 id="title">Myカレンダー管理画面</h1>
     <div id="infoLeft">
        <div>
            <p id="ym"><?php echo $y; ?><span><?php echo $m; ?></span></p>
            <p id="next"><a href="control.php">当月<span class="material-icons md-24">keyboard_arrow_right</span></a></p>
            <p id="view"><a target="_blank" rel="noopener" href="schedule2.php">プレビュー</a></p>
        </div>
        <p id="info">HTMLも入力できます。<br>リンクや画像も貼ってカスタマイズができます。入力後更新ボタンを押すと表示用のページに自動入力されます。変更の場合は上書きしてください。</p>
     </div>
     <form action="" method="post">
     <!-- トークンの値をvalueに -->
     <input type="hidden" name="csrf_token" value="<?php echo $token ?>">
     <table id="cale">
        <tr><?php
                foreach($week as $weeks){
                    echo '<td>'.$weeks.'</td>';
                }            
            ?>
        </tr>
        <?php
      // 1日の曜日を取得
            $wd1 = date("w", mktime(0, 0, 0, $m, 1, $y));
            // その数だけ空白を表示
            for ($i = 1; $i <= $wd1; $i++) {
            echo "<td> </td>";
            }

            // 1日から月末日までの表示
            $d = 1;
            $n = 0;

            //休日を共通にしたかったので別ファイルに
            require_once(dirname(__FILE__).'/holiday.php');
            //holiday.phpで祝日設定
            for($d = 1; $d <= $lastday; $d++) {
                echo '<td class="'.$holiday[$d].'"><span class="days">'.$d.'</span><textarea class="memo" name="name'.$n.'" value="'.$array[$n].'">'.$array[$n].'</textarea></td>';
                // 今日が土曜日の場合は…
                if (date("w", mktime(0, 0, 0, $m, $d, $y)) == 6) {
                    // 週を終了
                    echo "</tr>";
                    // 次の週がある場合は新たな行を準備
                    if (checkdate($m, $d + 1, $y)) {
                        echo "<tr>";
                    }
                }
                $n++;
            } 

            // 最後の週の土曜日まで移動
            $wdx = date("w", mktime(0, 0, 0, $m + 1, 0, $y));
            for ($i = 1; $i < 7 - $wdx; $i++) {
            echo "<td> </td>";
            }
        ?>
     </table>
     <p id="update"><input type="submit" value="更新する"></p>
     </form>
   </main>
   <footer>
       <small>Copyright 2020 All Rights Reserved. 無断転載禁止</small>
   </footer>
</div>  
</body>
</html>

カレンダープレビュー画面

ここは管理画面と作りはほぼ一緒。file_get_contents()でjsonからデータを取得してます。
翌月の方は省略します。

schedule.php
<?php
    date_default_timezone_set('Asia/Tokyo'); //東京時間にする
    $y = date('Y');
    $m = date('m')+0;
    $week = ['日','月','火','水','木','金','土'];
    $lastday = date('t', mktime(0, 0, 0, $m, 1, $y));

    //json取得
    $file = file_get_contents('./json/days'.$m.'.json');                                     $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
    $array = json_decode($data,true);

    //デコード
    function decode_html($word){
        return html_entity_decode($word);
    }

?>
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>スケジュールカレンダー | 当月</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="format-detection" content="telephone=no">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="common/reset.css">
    <link rel="stylesheet" href="common/style.css">
    <!--ファビコン32x32-->
    <link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon">
</head>
<body>
<div id="wrapper">
<header id="frontHeader">
    <h1 id="title">Myカレンダー予定表</h1>
    <p>管理画面から書き出されたものが表示されています。</p>
</header>
<main id="scheduleMain">
    <h2 id="ym"><?php echo $y; ?><span><?php echo $m; ?></span></h2>
    <p id="next"><a href="schedule2.php">翌月<span class="material-icons md-24">keyboard_arrow_right</span></a></p>
    <table id="cale">
        <tr>
            <?php
                foreach($week as $weeks){
                    echo '<td>'.$weeks.'</td>';
                }       
            ?>
        </tr>
        <tr>
        <?php
            // 1日の曜日を取得
            $wd1 = date('w', mktime(0, 0, 0, $m, 1, $y));
            // その数だけ空白を表示
            for ($i = 1; $i <= $wd1; $i++) {
                echo "<td> </td>";
            }
            // 1日から月末日までの表示
            $d = 1;
            $n = 0;
            //当月用休日設定
            require_once(dirname(__FILE__).'/holiday.php');
            //holiday.phpで祝日$holiday設定
            for($d = 1; $d <= $lastday; $d++){
                echo '<td class="'.$holiday[$d].'"><span class="days">'.$d.'</span><div class="memoUp">'.decode_html($array[$n]).'</div></td>';
                if (date("w", mktime(0, 0, 0, $m, $d, $y)) == 6) {
                    // 週を終了
                    echo "</tr>";
                    // 次の週がある場合は新たな行を準備
                    if (checkdate($m, $d + 1, $y)) {
                        echo "<tr>";
                    }
                }
                $n++;
            }
            // 最後の週の土曜日まで空欄を作る
            $wdx = date("w", mktime(0, 0, 0, $m + 1, 0, $y));
            for ($i = 1; $i < 7 - $wdx; $i++) {
            echo "<td> </td>";
            }
        ?>
        </tr>
    </table>
</main>
<footer>
       <small>Copyright 2020 All Rights Reserved. 無断転載禁止</small>
   </footer>
</div>
</body>
</html>

祝日の共通設定ファイル

ここは各ファイルに共通インクルードとして一つにしました。書き換えを楽にする為に。
Google APIを使うのも有りですが、独自で休日を入れたかったりローカルで編集したいこともあり自作しました。
Classの付与をif文で条件分岐させてます。
毎年手書きで更新する必要がありますが。。。

※6月から作ったので6月から記述してます。

holiday.php
<?php
//祝日の配列1
$holiday = [];
for($d; $d <= $lastday; $d++){
    $holiday[$d] = 'none';
    if($m === 6){//月
            $holiday[$d] = 'none';
    }
    if($m === 7 ){
        if($d === 23 || $d === 24){
            $holiday[$d] = 'holiday';
        } else {
            $holiday[$d] = 'none';
        }
    }
    if($m === 8){
        if($d === 10){
            $holiday[$d] = 'holiday';
        } else {
            $holiday[$d] = 'none';
        }
    }
    if($m === 9){
        if($d === 21 || $d ===22){
            $holiday[$d] = 'holiday';
        } else {
            $holiday[$d] = 'none';
        }
    }
    if($m === 10){
            $holiday[$d] = 'none';
    }
    if($m === 11){
        if($d === 3 || $d ===23){
            $holiday[$d] = 'holiday';
        } else {
            $holiday[$d] = 'none';
        }
    }
    if($m === 12){
        if($d === 23 || $d ===22){
            $holiday[$d] = 'holiday';
        } else {
            $holiday[$d] = 'none';
        }
    }
}

自動更新タイマー設定

これが一番大変でした。
postしたデータはDBに格納することが多いと思いますが、DBを使うまでもないしお手軽に組み込みたい。
でも外部データを使わないとpostデータは失われてしまう。
そこでjsonを使うことにしました。
json使うの初めてです。

管理画面もプレビュー画面もここからfile_put_contents()とfile_get_contents()でデータを上書き、取得しています。
月が変わった時、先月のデータを取ってきて当月に上書きし翌月は日付分の空文字を挿入。
タイマーはif文でstrtotime(date('Y-m-d H:i:s'))より大か小かで振り分けてますが、これでいいのかイマイチ不安。
小刻みのタイマーテストはしてみましたが、ひと月たったらちゃんと動いているかどうか…

サーバ上で時をみながら確認して、変わってなかったら考えることにします。気長にゆるゆる開発。

timer.php
<?php
//毎月1になったら自動でカレンダーを繰越し

//当月になったら先月のデーターを移行する
function daily($num){
    $file = file_get_contents('./json/days'.($num-1).'.json');
    $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); 
    $array = json_decode($data,true);
    $json = json_encode($array);
    file_put_contents('./json/days'.$num.'.json',$json);
}

//年初めの時
function start_daily($num){
    $file = file_get_contents('./json/days12.json');
    $data = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); 
    $array = json_decode($data,true);
    $json = json_encode($array);
    file_put_contents('./json/days'.$num.'.json',$json);
}

if(strtotime(date('Y-01-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-02-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    start_daily(1);

} elseif (strtotime(date('Y-02-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-03-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(2);

} elseif (strtotime(date('Y-03-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-04-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(3);

} elseif (strtotime(date('Y-04-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-05-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(4);

} elseif (strtotime(date('Y-05-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-06-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(5);

} elseif (strtotime(date('Y-06-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-07-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(6);

} elseif (strtotime(date('Y-07-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-08-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(7);

} elseif (strtotime(date('Y-08-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-09-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(8);

} elseif (strtotime(date('Y-09-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-10-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(9);

} elseif (strtotime(date('Y-10-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-11-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(10);

} elseif (strtotime(date('Y-11-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-12-01 00:00:00')) > strtotime(date('Y-m-d H:i:s'))){
    daily(11);

} elseif (strtotime(date('Y-12-01 00:00:00')) < strtotime(date('Y-m-d H:i:s')) && strtotime(date('Y-12-31 23:59:59')) > strtotime(date('Y-m-d H:i:s'))){
    daily(12);

} else {
    //json初期値とりあえず作っておく
    for($i=1; $i < 13; $i++){
    file_put_contents('./days/days'.$i.'.json',null);
    }
}

とりあえず作ってみて思ったこと

簡単なシステムでも、一つの形になるものを作るのってすごく難しいですね。
ほんの少し操作性がいいものを追加しようとすると2、3日は軽く悩む。
今までのコードは全て捨てて、新しく作り変えることも少なくないです。
まだまだ初心者なので知らないこともいっぱいあるし。

でも動いた時の感動は恐悦至極。これがあるからやめられない。
そろそろクラスやフレームワークも触ってみたいし、DBも挑戦してみようかななどと思っています。

就職が決まって6月下旬から働き始めたので、今までみたいにまとまった時間は作れなくなりました。
希望職のwebデザインですが仕事でプログラムを組むことは、まずなさそう。HTMLは触りますが。

でも開発はこれからも続けていくつもりです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DoctrineMigrationsBundle 2 → 3 メジャーバージョンアップ対応

概要

SymfonyアプリでDBマイグレーションをやってくれる DoctrineMigrationsBundle の3系が2020年06月にリリースされました。

2系から3系へのメジャーバージョンアップ対応を記します :pencil:

環境

  • PHP 7.2
  • Symfony 4.4
  • DoctrineMigrationsBundle 2.1.2 --> 3.0.1
  • MySQL 5.6

本題

変更点等は UPGRADE.md に記されています

doctrine/doctrine-migrations-bundle パッケージは
doctrine/migrations パッケージを require しているので、こちらの UPGRADE.md も読んでおくといいかもです

要点としては以下です

  • 『マイグレーションテーブルの更新』
    • テーブル名: これまで migration_versions がデフォルトでしたが、 doctrine_migration_versions がデフォルトになります(設定で変更可能)
    • カラム
      • version : これまで 20200601000000 のように YmdHis フォーマットでしたが、3系からは FQCN (Fully Qualified Class Name)になります
      • execution_time : 新規に追加されます。マイグレーションにかかった時間を格納するようです。既存の executed_at (マイグレーションを適用した日時)とは別カラムになります
  • Code BC Breaks
    • いくつかのクラスが final classになっていたり、削除されていたりします

『Code Bc Breaks』 については、各自のアプリケーションでの実装次第となりそうなので、
final classになったものについては継承する形式をやめて construct で内包する形に変更するなどの対応になるかと思います。

この記事では、
共通してつまづきそうな『マイグレーションテーブルの更新』について記します。

『マイグレーションテーブルの更新』に合わせて、 doctrine_migrtions の設定方法が変わりました :rotating_light:

変更点は主に以下の2つです
- マイグレーションファイルのディレクトリ・namespaceの設定方法の変更
- マイグレーションテーブルの設定方法の変更

マイグレーションファイルのディレクトリ・namespaceの設定方法の変更

マイグレーションファイルを保存してあるディレクトリに合わせて以下の設定を加えます

After は、デフォルトの値になるので、各自アプリケーションでのディレクトリ・namespaceに合わせて設定する必要があります

デフォルトと異なる場合、合わせて指定してあげないと「マイグレーションファイルが存在しない」と認識されエラーになります

Before ※ 元々、設定がない場合もあります

doctrine_migrations:
    dir_name: '%kernel.project_dir%/src/Migrations'
    namespace: DoctrineMigrations

After

doctrine_migrations:
    migrations_paths:
        DoctrineMigrations: '%kernel.project_dir%/src/Migrations'
        # ? ここが {namespace}: {dir_name} となるように設定します

例えば、以下のようなファイル構成と namespace であれば、デフォルトのままで問題ないですが、
どちらかでもカスタムしていれば合わせて設定してください

% tree ./path_to_app/src
..
├── Migrations  # ? {dir_name} として設定
│   ├── Version20200601000000.php 
│   ├── Version20200602000000.php 
..
namespace DoctrineMigrations; # ? {namespace} として設定

final class Version20200601000000 extends AbstractMigration
{
  .. 

マイグレーションテーブルの設定方法の変更

次にマイグレーションテーブルの設定方法も変更になりました。

デフォルトのテーブル名が migration_versions から doctrine_migration_versions に変わったので、
既存のマイグレーションテーブルをそのまま使うのであれば、指定してあげる必要があります。

Before ※ 元々、設定がない場合もあります

doctrine_migrations:
    table_name: 'migration_versions'
    column_name: 'version'
    column_length: 14
    executed_at_column_name: 'executed_at'

After

doctrine_migrations:
    storage:
        table_storage:
            table_name: 'migration_versions'       # 注意①
            version_column_name: 'version'         # 元々、versionsカラムであれば指定しなくても大丈夫です
            version_column_length: 191             # 注意②
            executed_at_column_name: 'executed_at' # 元々、executed_atカラムであれば指定しなくても大丈夫です

注意① table_name

3系からデフォルトのマイグレーションテーブルのテーブル名は doctrine_migration_versions に変更されます。

おそらく(?)みなさんのマイグレーションテーブルのテーブル名は指定して作成していなければ migration_versions のはずなので、
3系からは設定で指定してあげる必要があります。

そうとは知らず、省略していると、 doctrine_migration_versions テーブルが新規作成され、1からマイグレーションが実行されてしまうので注意してください :rotating_light:

注意② version_column_length

3系から version カラムに入る値は 20200601000000 のように YmdHis フォーマットではなく FQCN になります。

2系のカラム長のデフォルト値 14 のままでは、 FQCN が入り切らない可能性があるため、3系では増えました。

UPGRADE.md に記載のあるように 1024 を設定しまうと、 MySQL 5.6 ではエラーになってしまうので注意してください :rotating_light:

理由は、MySQL 5.6の単一カラムのインデックスキーは 767byte までしか指定できないからです。

なので 191 (191文字 * 4byte = 764byte < 767byte) ※ 4byte文字を考慮


execution_time カラムが追加されたこともあり、マイグレーションテーブルの2系と3系でどう変わるのか?は実際のデータを見てもらうのが早いので、以下に示します

2系

mysql> select * from migration_versions;
+----------------+---------------------+
| version        | executed_at         |
+----------------+---------------------+
| 20200601000000 | 2020-06-01 00:01:00 |
| 20200602000000 | 2020-06-02 00:01:00 |
..

3系

mysql> select * from migration_versions;
+------------------------------------------+---------------------+----------------+
| version                                  | executed_at         | execution_time |
+------------------------------------------+---------------------+----------------+
| DoctrineMigrations\Version20200601000000 | 2020-06-01 00:01:00 |             11 |
| DoctrineMigrations\Version20200602000000 | 2020-06-02 00:01:00 |             12 |
..

doctrine:migrations:migrate または doctrine:migrations:execute 実行時に、
3系のマイグレーションテーブルへ更新されます

execution_time カラムが追加されるだけではなく、
適用済みのマイグレーションの version の値についても、 FQCN への更新がされます!

1からマイグレーションが再実行されるわけではないのでご安心を。

以上で、『マイグレーションテーブルの更新』まわりでのメジャーバージョンアップ対応は完了になります。

ほとんどのケースで、これで対応完了になるのではないかと思っております :thought_balloon:


マイグレーションファイルでサービスコンテナを利用している場合

ここからは、少しレアケースで、なんらかの理由でマイグレーションファイルでサービスコンテナを利用している場合、
追加で対応してあげる必要があります

これまでは、以下のように ContainerAwareInterface を implements して use ContainerAwareTrait を宣言すれば、
自動でサービスコンテナがセットされていました。

が、3系からは自動でセットされません :confused:

class Version20200601000000 extends AbstractMigration implements ContainerAwareInterface
{
    use ContainerAwareTrait;

対応方法はこちらMigration Dependencies に記載されています

マイグレーション実行時にマイグレーションインスタンスの生成を
MigrationFactory 経由で生成しているところを、これを装飾した MigrationFactoryDecorator 経由に変更する(エイリアスをはる)ことで、
デコレータの装飾部分で ContainerAwareInterface のインスタンスであれば、サービスコンテナをセットするといった感じです。

        doctrine_migrations:
            services:
                 'Doctrine\Migrations\Version\MigrationFactory': 'App\Migrations\Factory\MigrationFactoryDecorator'
                 # ? MigrationFactory として MigrationFactoryDecorator を使用するように変更
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelを用いた開発環境の構築手順

Laravelを用いたプロジェクトの開発手順です。

Laravelのインストール

Composerを使用して、グローバル環境にLaravelをインストールします。

$ composer global require laravel/installer

laravel実行ファイルがどこに設置されても動作するように、composerシステム全体のvendor/binディレクトリに$PATHを登録します。
MACの場合は、下記をターミナルで記述します。

$ export PATH=$HOME/.composer/vendor/bin:$PATH

プロジェクトの作成

cdでプロジェクトを作成するディレクトリに移動して、laravel new プロジェクト名を実行します。

$ cd htdocs
$ laravel new quick_laravel

インストールされたアプリの確認

インストールが完了すると、このようにディレクトリにファイルが作成されます。

Screen Shot 0032-07-05 at 18.16.48.png
メインとなるアプリやディレクトリは、下記のようにそれぞれの役割があります。
.
├── app … アプリ本体コード
│ ├── Console … コンソールアプリ
│ ├── Exception … 例外処理関連
│ ├── Http … webアプリ
│ │ ├── Controllers … コントローラー(リクエストを受け取り、モデルを呼んだりビューに表示をさせる)
│ │ ├── Middleware
│ │ └── Kernel.php
│ ├── Prociders … プロバイダー関連
│ └── User.php
├── bootstrap … アプリ起動時に実行されるコード
├── cofig … アプリの共通設定
├── database … データベース関連
├── public … 公開するディレクトリ(Js、CSS)
├── resources … アプリのリソース関連(Viewファイルなど)
├── routes … ルーティング関連(ルーター:リクエストURLに応じて受け渡し先を決める)
├── storage … アプリが操作するファイルの保存先
├── tests … テストコード関連
├── vendor … Laravel本体とライブラリコード
├── artisan … artisanコマンドの設定
├── composer.json … composerの設定
├── package.json … npmの設定
├── phpunit.xml … テストツールの設定
└── server.php … サーバー起動時に実行するコード

サーバーの起動

php artisan serveでサーバーが立ち上がります。

$ php artisan serve

この画面が出たら、OKです。

Screen Shot 0032-07-05 at 18.10.53.png

サーバーは、ctr + cで終了できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP クラスの使い方 勉強メモ

クラスの使い方のmemo

クラスの使い方
// クラス
class Post
{
  // プロパティ
  private $text;
  private $likes;

  // コンストラクタ
  public function __construct($text, $likes)
  {
    $this->text = $text;
    $this->likes = $likes;
  }

  // メソッド
  public function show()
  {
    printf('%s (%s)' . PHP_EOL, $this->text, $this->likes);
  }
}

//ここで値を渡す
$posts[0] = new Post('hello', 0);
$posts[1] = new Post('hello again', 1);

//Postクラスのshowメソッドを実行
$posts[0]->show();
$posts[1]->show();

出力される値
hello (0)
hello again (0)

コンストラクタ

・newしたときに実行される特殊なメソッド

クラスを定義する理由

・修正を加えるときに影響範囲がわかりやすい。(コードの見通しがよくなる)

アクセス修飾子

*初期値や何も記載しない場合は、public
*意図しない使われ方をしないために、privatがいいかも。

public

クラスの中でも外でも使える

private

クラス内でしか使えない変数に定義する。

protected

親クラスと子クラスで使える

継承

final

メソッドをオーバーライドしてほしくないときに利用する
例:

final public function test() {
   echo 'test';
}

参考
ドットインストール
https://dotinstall.com/lessons/basic_php_objects/54004

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker上のcomposer install時にメモリ不足をお手軽に解消する Tips

結論

$ COMPOSER_MEMORY_LIMIT=-1 composer install
  • COMPOSER_MEMORY_LIMIT=-1をオプションにつけて実行する

参照記事とか

docker上のphpコンテナでcomposer installしたら、メモリ不足で落ちた話
を参照に、php.iniを編集しても問題はありませんでしたが、もっとお手軽な方法が。

php.ini
  memory_limit = -1

composerにはCOMPOSER_MEMORY_LIMITの環境変数が使える

$ COMPOSER_MEMORY_LIMIT=-1 composer install

composer updateでmemoryが足りない場合の対応方法 その2

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FizzBuzz問題ーPHP初級編ー

はじめに

FizzBuzz問題、1度は耳にしたことがある方が多いのではないかと思います。
今回はそのFizzBuzz問題を解説していきたいと思います。

そもそもFizzBuzz問題とは

英語圏で行われている言葉遊びの一種のようですね。

プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3の倍数では「Fizz」(Bizz Buzzの場合は「Bizz」)、5の倍数では「Buzz」、両者の公倍数(すなわち15の倍数)では「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。

引用:Fizz Buzz - Wikipedia

このゲームをプログラミングに応用したものが「Fizz Buzz問題」です。
プログラマーの基本的な知識を確認するのに、面接の小テストで用いられることもあります。

早速FizzBuzz問題を解いてみよう

【問題】
- 1から100までの数をプリントするプログラム
- 3の倍数の時には数の代わりに「Fizz」とプリントする
- 5の倍数の時には数の代わりに「Buzz」とプリントする
- 3と5両方の倍数の時には数の代わりに「FizzBuzz」とプリントする

【回答】
※今回は理解しやすい簡単なものを例に挙げています。
※PHPのバージョンは7系を前提としています。

//そのファイル内での関数呼び出しの際に厳密モードでの型検査が行われるようにする
declare(strict_types=1);

//1から100までの数を繰り返す
for ($i = 1; $i <= 100; $i++) {
    //3と5両方の倍数の(15の倍数)なら
    if ($i % 15 === 0) {
        echo 'FizzBuzz';
    //3の倍数のなら
    } elseif ($i % 3 === 0) {
        echo 'Fizz';
    //5の倍数のなら
    } elseif ($i % 5 === 0) {
        echo 'Buzz';
    //上記以外
    } else {
        echo $i;
    }
    //見やすいように改行
    echo PHP_EOL;
}

おわりに

いかがでしたでしょうか。
いったん1つの言語で理解すれば他の言語にも応用がきくと思うので仕組みを理解しておくことは大事でしょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP入門 - お問い合わせフォームを作ろう (2)

php.png

前回の続きです。

セッション変数の利用

お問い合わせフォームに入力した内容を確認画面に渡すためにコードを追加します。

index.php
<?php
session_start(); // 追記
$error = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

    if ($post['name'] === '') {
        $error['name'] = 'blank';
    }
    if ($post['email'] === '') {
        $error['email'] = 'blank';
    } else if (!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) {
        $error['email']= 'email';
    }
    if ($post['contact'] === '') {
        $error['contact'] = 'blank';
    }

    if (count($error) === 0) {
        $_SESSION['form'] = $post; // 追記
        header('Location: confirm.php');
        exit();
    }
}
?>

これでindex.phpはとりあえず完成です。(あとでまた編集します)

次はconfirm.phpを編集していきます。

セッション変数の受け取り

まずはindex.phpから送られてきた値を受け取れるようにします。

<!DOCTYPE>の上にコードを追加します。

confirm.php
<?php
session_start();

$post = $_SESSION['form'];
?>

続いて、受け取った値を表示できるようにしましょう。一気にやっていきます。

confirm.php
<body>
    <div class="container">
        <form action="./confirm.php" method="POST">
            <h4 class="py-4 text-center">確認画面</h4>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputName">お名前</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p><?php echo htmlspecialchars($post['name']); ?></p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputEmail">メールアドレス</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p><?php echo htmlspecialchars($post['email']); ?></p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputContent">お問い合わせ内容</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p><?php echo nl2br(htmlspecialchars($post['contact'])); ?></p>
                    </div>
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-8 col-offset-2">
                    <a href="index.php" class="btn btn-primary rounded-0">戻る</a>
                    <button type="submit" class="btn btn-primary rounded-0">送信する</button>
                </div>
            </div>
        </form>
    </div>
</body>

動作確認をしましょう。何も問題がなければ、下の画面のように、お問い合わせフォームに入力した内容がきちんと反映されます。

img1.png

確認画面が直接呼ばれたときの対処

今のままだと、comfirm.phpが直接呼び出されたときに、内容が空っぽのまま表示されてしまいます。

そこで、入力画面からのアクセスでない場合、index.phpが表示されるようにします。

confirm.php
<?php
session_start();

if (!isset($_SESSION['form'])) {
    header('Location: index.php');
    exit();
} else {
    $post = $_SESSION['form'];
}
?>

上記のコードを追加すれば、対処は完了です。

戻るボタンを押したときの対処

確認画面で戻るボタンを押すと、入力していた値が消えてしまいます。これはGETで呼び出されるからです。

というわけで、index.phpにコードを追加します。

index.php
<?php
session_start();
$error = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

    if ($post['name'] === '') {
        $error['name'] = 'blank';
    }
    if ($post['email'] === '') {
        $error['email'] = 'blank';
    } else if (!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) {
        $error['email']= 'email';
    }
    if ($post['contact'] === '') {
        $error['contact'] = 'blank';
    }

    if (count($error) === 0) {
        $_SESSION['form'] = $post;
        header('Location: confirm.php');
        exit();
    }
} else { // ここから
    if (isset($_SESSION['form'])) {
        $post = $_SESSION['form'];
    }
} // ここまで
?>

実際に確認画面で戻るボタンを押してみて、動作を確認してみてください。

メール送信

confirm.phpで「送信する」ボタンを押したときの処理を書いていきます。

今回は実際にメールの送信までは行いませんので、興味のある方は自分で調べてみてください。

まず、action属性を空にします。

confirm.php
<form action="" method="POST">

次にPHPのコードを追加します。

confirm.php
<?php
session_start();

if (!isset($_SESSION['form'])) {
    header('Location: index.php');
    exit();
} else {
    $post = $_SESSION['form'];
}
// ここから
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $to = 'test@example.com';
    $from = $post['email'];
    $subject = 'お問い合わせが届きました';
    $body = <<<EOT
名前: {$post['name']}
メールアドレス: {$post['email']}
内容:
{$post['contact']}
EOT;
    var_dump($body);
    exit(); 

    mb_send_mail($to, $subject, $body, "From: {$from}");

    unset($_SESSION['form']);
    header('Location: thanks.html');
    exit();
}
// ここまで
?>

今回はメールを送信する代わりにvar_dumpで送信内容を確認してみましょう。

確認画面の「送信する」ボタンを押すと、

img2.png

送信内容を見ることができます。

お礼画面への移動

var_dumpとexit()とmb_send_mailをコメントアウトしておきます。(このままだとエラーが起きるため)

confirm.php
// var_dump($body);
// exit();
// mb_send_mail($to, $subject, $body, "From: {$from}");

thanks.htmlを作成します。

thanks.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>お礼画面</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <p class="lead mt-5 mx-auto">
                お問い合わせありがとうございました。<br>
                後ほど、担当者よりご連絡をさせていただきます。<br>
            </p>
        </div>
    </div>
</body>
</html>

確認画面の「送信する」ボタンを押すと、お礼画面に移動します。

img3.png

これでお問い合わせフォームは完成です。完成品のソースコードはここで見ることができるので、よかったらご覧ください。

最後に

PHPはいかがだったですか?

「案外簡単じゃん」と思った人も、「けっこう難しい」と感じた人も、これを機にPHPで(あるいは、ほかの言語でも)何かプログラムを作ってみたいと思ってくれたら幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

高品質なPMMPプラグインを作るコツ

はじめに

PMMP(Poggit)が制定している、PQRS (Plugin Quality Requirement Standards)と呼ばれるプラグイン品質の要件標準があります。
これは、それを翻訳して一般的なプラグイン向けにまとめて解説しているものです。

※移動や変更を繰り返したのちPoggitのSubmission Rulesとなっていますが、今でも実質的にPMMPプラグインのPQRSと言えます。

注意: この記事では、RFC 2119 や RFC 6919 に則って要件レベルを表しているわけではありません。

冗長なAPIバージョン

プラグインは、plugin.ymlに冗長なAPIバージョンを指定してはいけません。
各メジャーバージョンでサポートされている最も古いAPIバージョンのみを指定する必要があります。
例えば、「3.1.0」が既に指定されている場合、「3.2.0」は不要です。

  • 悪い例
plugin.yml
api:
  - 3.1.0
  - 3.2.0
  • 良い例
plugin.yml
api:
  - 3.1.0

まず前提として、plugin.ymlのapiディレクティブは以下のような仕様になっています。

  • 3.0.0を指定してある場合: 3.0.0 => ○ | 3.1.0 => ○ | 3.12.0 => ○
  • 3.5.0を指定してある場合: 3.0.0 => × | 3.4.5 => × | 3.5.0 => ○ | 3.12.0 => ○
  • 3.12.0を指定してある場合: 3.0.0 => × | 3.4.5 => × | 3.5.0 => × | 3.12.0 => ○

これが何故かというと、現在のPMMPではセマンティック バージョニングを採用しているからです。
この方式は、メジャー.マイナー.パッチとしてバージョニングする決まりです。
要約すると以下の通りです。

  • 後方互換性の無い変更の場合: メジャーバージョンが上がります(例: 3.1.0 => 4.0.0)
  • 後方互換性のある変更(主に機能追加)の場合: マイナーバージョンが上がります(例: 3.1.0 => 3.2.0)
  • 後方互換性のある変更(主にバグ修正)の場合: パッチバージョンが上がります(例: 3.1.0 => 3.1.1)

このように、メジャーバージョンの変更以外では後方互換性があるため、複数指定する必要はないわけです。
前方互換性はもちろんないので、とりあえず「3.0.0」と指定したり、現在の最新バージョンなどを指定するのはあまり適切ではありません。「3.1.0」で追加された機能を使用したい場合は「3.1.0」と指定し、「3.12.0」で追加された機能を使用したい場合は「3.12.0」と指定する必要があります。

APIバージョンには、サポートされている最も古いAPIバージョンを指定する必要があります。
最低限要求されるAPIバージョンにすることで、幅広いバージョンで動作させることが出来ます。

PMMPのソースコードを注意深く読んでいると、関数が@ deprecatedになっていたりしますが、その関数が削除されないで残っている(その関数の内部で新規追加された関数などをラップして呼び出していることが多い)のはこの後方互換性を維持するためです。
(例えば、addTitle関数がsendTitle関数に変更されても、addTitle関数は非推奨なものの、引き続き同じように使用できる)

鋭い方は、「APIバージョンを複数指定できる意味はあるのか?」と感じるかもしれません。
これは、APIバージョンがALPHAである場合などに使用されます。
(これはよくある例であって、メジャーバージョンにも同じことが言えます)

3.0.0-ALPHA1や2などのAPIバージョンを見かけたことはあるでしょうか。
このバージョンでは、毎回APIの後方互換性が失われます。(毎回メジャーバージョンが上がるようなイメージです)
そのため、「3.0.0-ALPHA5」を指定したら「3.0.0-ALPHA6」でも動くといったシステムにはできません。
つまり、ALPHAバージョンが変わるたびに使っている機能に変更がないか確認する必要があります。

plugin.yml
api:
  - 3.0.0-ALPHA1
  - 3.0.0-ALPHA2
  - 3.0.0-ALPHA3
  - 3.0.0-ALPHA4

このときに複数指定する必要が出てくるわけです。
すこし話がずれますが、まれに「3.0.0」と「4.0.0」を両方指定することがあります。
この行為自体は悪いことではないのですが、自分が使っている機能が「3.0.0」でも「4.0.0」でも使用できることをしっかり確認するようにしてみてください。

起動/停止での無駄なメッセージ

プラグインは、起動/停止に本当に時間がかかる場合(概ね1秒程度)を除いて、「有効になりました」や「製作者: xxx」などの不要なメッセージを出力してはいけません。

これは、コンソールを無駄に汚さないための配慮です。
例えば、一般的なメッセージで「赤や黄や青」などを使用したとします。
するとユーザーは本当のエラーや警告に気付くことができなくなってしまいます。

コンソールを注意深く見ていると、プラグインが有効になったとき、PMMPによって「[00:00:00] [Server Thread/INFO]: <プラグイン名> を有効にしています」などが自動的に出力されていることが分かります。
それを再度プラグインから出力する必要があるか考えてみてください。

では、プラグインを有効にしていることではなく、プラグインが有効になった(有効化が完了した)ことをユーザーに伝えたいかもしれません。
例えば虹色と複数行のASCIIアートなどで派手なメッセージを作成する必要がありますか?

派手なメッセージを作成することによって、プラグインの素晴らしさを伝えたいかもしれません。
しかし、サーバー上のほかのすべてのプラグインも同じことをしました。

ロガーには標準で色が付いています。(例えば、NOTICEは青、WARNINGは黄色、ERRORは赤など)

さらに詳細を知りたい方はこちらのスレッドも確認してみてください。

依存関係を宣言

プラグインは、plugin.ymlで依存関係を宣言します。

これによって、必須プラグインが無い状態でプラグインが読み込まれることを防げます。

  • 一般的な処理
public function onEnable() {
  $this->money = $this->getServer()->getPluginManager()->getPlugin("EconomyAPI");
  if ($this->money === null) {
    $this->getLogger()->error("EconomyAPIが読み込まれていません!");
    $this->getServer()->shutdown();
  }
}
  • 推奨される処理
plugin.yml
depend:
  - EconomyAPI
  - FormAPI

こうすることで、ここにあるプラグインが存在しなかった場合に「不明な依存関係です:<プラグイン名>」などの形で表示され、自動的にプラグインは無効化されます。プラグイン側でわざわざそのような処理を書く必要はありません。

メインスレッドをブロック

プラグインは、起動/停止時を除いて、スレッドが応答を待機するような処理でメインスレッドをブロックしないようにする必要があります。
小規模なローカルI/O処理(PocketMineで使用される範囲と比較)を除いて、メインスレッドをブロックする処理(cURL呼び出し、重いMySQLクエリ、重いSQLiteクエリ、playersスキャンなど)はメインスレッドで実行できません。

これは、時間が掛かる処理では非同期処理を使おうということです。
例えば、cURLなどでWEB APIを呼ぶ場合などです。
メインスレッドでこのような処理を行うと、その間何も処理されなくなってしまうので、当たり前ですがサーバーが重くなります。
そのため、非同期処理(AsyncTaskやThread)などを効率的に使用する必要があります。

名前空間の形式

プラグインは、他のプラグインと衝突しない一意な名前空間を使用する必要があります。
作者名で始まり、その後に対応するプラグインを続けた名前空間にする必要があります。
推奨される名前空間の形式は、製作者名\プラグイン名です。
衝突を防ぐために、製作者名にはGitHubのユーザー名や組織名、名前などに対応するものを使用する必要があります。
公式のプラグインでない限り名前空間「pocketmine」は許可されていません。

  • 悪い例
Main.php
<?php

namespace src\FooPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase {}
Main.php
<?php

namespace pocketmine\FooPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase {}
  • 良い例
Main.php
<?php

namespace Steve\FooPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase {}

名前空間の中に留まる

プラグインによって宣言されたすべてのクラス、インターフェース、トレイトは、名前空間の形式に基づいて決めたこの一意の名前空間の下にある必要があります。これは、プラグインにライブラリを内蔵している場合も含まれます。
ただし、プラグインにライブラリを内蔵させるのではなく、Virionフレームワークを使用することも検討してください。

  • 悪い例

  • Steve\FooPlugin\Main

  • Steve\FooPlugin\EventListener

  • Steve\FooLibrary\API

  • 良い例

  • Steve\FooPlugin\Main

  • Steve\FooPlugin\EventListener

  • Steve\FooPlugin\Library\API

名前空間の変更

名前空間の変更を必要とするほどの巨大な変更がない限り、一度リリースしたらプラグインの名前空間を変更しないでください。
それがしたい場合、開発者は古いバージョンを廃止し、代わりに新規プラグインを送信することをお勧めします。

  • 悪い変更例(同じプラグインのままで)

  • Steve\FooPlugin\Main

  • Steve\FooPlugin\EventListener

  • Steve\FooPl\Main
  • Steve\FooPl\EventListener

コマンドのfallbackPrefix

プラグインが、CommandMap->registerを直接呼び出してコマンドを登録する場合、この関数に渡されるfallbackPrefixパラメータはプラグイン名でなければいけません。プラグインは、fallbackPrefixにイニシャルなどを使用出来ません。

※plugin.ymlでコマンドを登録している場合は、これについて考慮する必要はありません。

  • 悪い例
public function onEnable() {
  $this->getServer()->getCommandMap()->register("say", new SayTheMessageCommand("say", $this));
}
public function onEnable() {
  $this->getServer()->getCommandMap()->register("FooPlugin-Command", new SayTheMessageCommand("say", $this));
}
  • 良い例
public function onEnable() {
  $this->getServer()->getCommandMap()->register($this->getName(), new SayTheMessageCommand("say", $this));
}

もしくは

public function onEnable() {
  $this->getServer()->getCommandMap()->register("FooPlugin", new SayTheMessageCommand("say", $this));
}

Plugin-identifiable

全てのコマンドは、PluginIdentifiableCommandインターフェースを実装し、プラグインのインスタンスを返す必要があります。

※プラグインのメインクラスでコマンドを実装している場合は、これについて考慮する必要はありません。

これは、多くの場合はPluginCommandクラスを継承して作成しようということです。
PluginCommandには、既にPluginIdentifiableCommandが実装されているためです。
例えば、Commandクラスを継承してコマンドを実装する場合などには、別途PluginIdentifiableCommandインターフェースを実装する必要があります。

  • 悪い例
<?php

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\plugin\Plugin;

class SayTheMessageCommand extends Command
{
    /** @var Plugin */
    private $plugin;

    public function __construct(string $name, Plugin $plugin)
    {
        parent::__construct(
            $name,
            "description",
            "usageMessage"
        );
        $this->plugin = $plugin;
    }

    public function execute(CommandSender $sender, string $commandLabel, array $args)
    {
        $this->plugin->getServer()->broadcastMessage("Hello!");
    }
}
  • 良い例
<?php

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\plugin\Plugin;

class SayTheMessageCommand extends Command implements PluginIdentifiableCommand
{
    /** @var Plugin */
    private $plugin;

    public function __construct(string $name, Plugin $plugin)
    {
        parent::__construct(
            $name,
            "description",
            "usageMessage"
        );
        $this->plugin = $plugin;
    }

    public function execute(CommandSender $sender, string $commandLabel, array $args)
    {
        $this->plugin->getServer()->broadcastMessage("Hello!");
    }

    public function getPlugin(): Plugin
    {
        return $this->plugin;
    }
}

もしくは

<?php

use pocketmine\command\Command;
use pocketmine\command\CommandExecutor;
use pocketmine\command\CommandSender;
use pocketmine\command\PluginCommand;
use pocketmine\plugin\Plugin;

class SayTheMessageCommand extends PluginCommand implements CommandExecutor
{
    public function __construct(string $name, Plugin $owner)
    {
        parent::__construct($name, $owner);
        $this->setExecutor($this);
    }

    public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool
    {
        $this->getPlugin()->getServer()->broadcastMessage("Hello!");
        return true;
    }
}

パーミッション名

プラグインがパーミッションを登録する場合、すべてのパーミッション名はプラグイン名で始まる必要があります。
名前空間のように製作者名を含める必要はありません。
パーミッション名は、アルファベット、数字、ハイフン、ドットのみで構成する必要があります。

  • 悪い例

  • Steve.FooPlugin.Command.say

  • Say.The.Message.Command

  • SayCommand

  • FooPlugin@SayTheMessageCommand

  • FooPlugin.SayTheMessage!Command!12345

  • 良い例

  • FooPlugin.Command.say

  • FooPlugin.Say.The.Message.Command

  • FooPlugin.SayCommand

  • FooPlugin-SayTheMessageCommand

  • FooPlugin.SayTheMessage-Command12345

永続的データの名前空間

プラグインの一般的なデータは、プラグインのデータフォルダ内に保存する必要があります。
エンティティ/アイテム固有のデータ(NBT)は、プラグイン名が指定された固有のCompoundTag内に保存する必要があります。
外部に保存されたデータ(MySQLなど)は、他プラグインとの衝突を防ぐために、できるだけプラグイン名を前につけた構成にする必要があります。

これは、プラグイン間での競合を防ぐためです。

データフォルダ

  • 悪い例
<?php

use pocketmine\plugin\Plugin;

/** @var Plugin $plugin */

file_put_contents("C:\\Foo\\Bar\\example.txt", "HogeFuga");

//pluginsやplugin_nata、worldsフォルダなどがあるフォルダに、example.txtを作成しています。
file_put_contents($plugin->getServer()->getDataPath() . "example.txt", "HogeFuga");
  • 良い例
<?php

use pocketmine\plugin\Plugin;

/** @var Plugin $plugin */

file_put_contents($plugin->getDataFolder() . "example.txt", "HogeFuga");

NBT

  • 悪い例
<?php

use pocketmine\entity\Entity;

/** @var Entity $target */
$target->namedtag->setString("message", "こんにちは!");

var_dump($target->namedtag->getString("message"));//string("こんにちは!")
  • 良い例
<?php

use pocketmine\entity\Entity;
use pocketmine\nbt\tag\CompoundTag;

/** @var Entity $target */
$pluginTag = new CompoundTag("FooPlugin");
$pluginTag->setString("message", "こんにちは!");
$target->namedtag->setTag($pluginTag);

var_dump($target->namedtag->getCompoundTag("FooPlugin")->getString("message"));//string("こんにちは!")

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

先輩に用意してもらったDockerFileを使用してLaravel6の環境を作成した話

目的

  • 先輩の記事を参考にLaravel6の環境をDockerを用いて作成した話をまとめる

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB

前提条件

  • 特になし。

前提情報

読後感

  • Dockerコンテナ内のnginxのドキュメントルートディレクトリに「app」と言う名前のLaravel6のアプリを作成する。

概要

  1. Docker Desktop for Macのインストール
  2. DockerFileのcloneとコンテナの起動
  3. Laravelインストーラの取得
  4. Laravelのインストールとアプリ作成
  5. 確認

 詳細

  1. Docker Desktop for Macのインストール
    1. 下記の手順を参考にDocker Desktop for Macをインストールする。
  2. DockerFileのcloneとコンテナの起動とログイン
    1. 下記の先輩の記事の「Docker環境を作ろう」の部分を参考に全て実施して必要ファイルのcloneとコンテナの起動・コンテナへのログインを行う。
  3. Laravelインストーラの取得
    1. 下記の先輩の記事の「Laravelのインストーラーをインストールしよう」の部分を参考に全て実施してインストーラーを取得する。
  4. Laravelのインストールとアプリ作成

    1. 下記のコマンドを実行してnginxのドキュメントルートディレクトリに移動する。

      $ cd /usr/share/nginx/html
      
    2. 下記コマンドを実行してLaravelのインストールとアプリ作成を行う。

      $ composer create-project --prefer-dist laravel/laravel app "6.*"
      
    3. さきのコマンド実行完了後、作成されたappディレクトリに移動して下記コマンドを実行しアプリケーションキーを作成する。

      $ php artisan key:generate
      
  5. 確認

    1. appディレクトリにて下記コマンドを実行しLaravelのバージョンが6.Xになっていることを確認する。

      $ php artisan -V
      
    2. ブラウザにてhttp://localhost:8080にアクセスし、下記の画面が出ることを確認する。

      Laravel.png

    3. 作成されたappディレクトリに移動して下記コマンドを実行しアプリケーションキーを作成する。

      $ php artisan key:generate
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPファイルがブラウザで正しく表示されない

phpファイルをブラウザで表示させようとしたところ、

Image from Gyazo

ソースコードしか表示されなくて地味にハマったので

対処法を自分用に保存。

apacheを起動

まずPHPはサーバーサイド言語のため
当然ながらWEBサーバーを動かさなければお話なりません。

ドキュメントルート変更

apacheはデフォルトでMAMP/htdocs/index.phpファイルが起動するようになってるでこれを変更します。
Image from Gyazo

1 :MAMP選択 ➡️ prefecturesを選択

2 :Web Serverを選択

3 :ドキュメントルートを表示させたいファイルに選択。

以上。

フレームワークの恩恵を受けていると
サーバーやネットワークの知識が浅いことを痛感させられますな。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む