郵便番号:/^[0-9]{3}-[0-9]{4}$/
電話番後:/^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$/
E-mailアドレス:|^[0-9a-z_./?-]+@([0-9a-z-]+\.)+[0-9a-z-]+$|
Category: PHP
filter_var(), FILTER_VALIDATE_EMAIL
The filter_var() function filters a variable with the specified filter.
Returns the filtered data on success, or FALSE on failure.
The FILTER_VALIDATE_EMAIL filter validates an e-mail address.
<?php $email = "john.doe@example.com"; if (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) { echo("$email is a valid email address"); } else { echo("$email is not a valid email address"); } ?>
phpでMySQLに接続する書き方
phpでMySQLに接続, sql文にてデータを挿入する書き方例
$stmt->executeにて実行しています。変数の$dbhはdbhandlerの略です。
try { $dbh = new PDO('mysql:host='/DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASSWORD); } else (PDOException $e){ echo $e->getMessage(); exit; } $stmt = $dbh->prepare("select * from users where instagram_user_id=:user_id limit 1"); $stmt->execute(array(":user_id"=>$json->user->id)); $user = $stmt->fetch(); if (empty($user)){ $stmt = $dbh->prepare("insert into users(instagram_user_id, instagram_user_name, instagram_profile_picture, instagram_access_token, created, modified) values (:user_id, :user_name, :profile_picture, :access_token, now(), now());"); $pramas = array( ":user_id" =>$json->user->id, ":user_name" =>$json->user->username, ":profile_picture" =>$json->user->profile_picture, ":access_token"=>$json->access_token ); $stmt->execute($params);
データの取得
$stmt = $dbh->prepare("select * from users where id=:last_insert_id limit 1"); $stmt->execute(array(":last_insert_id"=>$dbh->lastInsertId())); $user = $stmt->fetch();
ログイン機能の実装
下のキャプチャのように、controller, model, viewにファイルを分けて作成しています。サインインデータはMysqlに格納して、ログイン時に呼び出して、判別しています。また、PostとGetでトークンの正誤判定も行っています。
controller.php
<?php namespace MyApp; class Controller { private $_errors; private $_values; public function __construct(){ if(!isset($_SESSION['token'])){ $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16)); } $this->_errors = new \stdClass(); $this->_values = new \stdClass(); } protected function setValues($key, $value){ $this->_values->$key = $value; } public function getValues(){ return $this->_values; } protected function setErrors($key, $error){ $this->_errors->$key = $error; } public function getErrors($key){ return isset($this->_errors->$key) ? $this->_errors->$key : ''; } protected function hasError(){ return !empty(get_object_vars($this->_errors)); } protected function isLoggedIn() { // $_SESSION['me'] return isset($_SESSION['me']) && !empty($_SESSION['me']); } public function me(){ return $this->isLoggedIn() ? $_SESSION['me'] : null; } }
投票システム (1日1回)
jqueryのclick functionでopacityを変更し、更にformのvalueにidを入れて、ボタンが押されたら、MySQLにIDを格納します。そして、Mysqlからsql文でデータを読み込んで、集計結果を表示させます。また、IPアドレス、ユーザーエージェント、データで、複数投票を制限しています。
-reference
bindValue:Binds a value to a corresponding named or question mark placeholder in the SQL statement that was used to prepare the statement.
SQL INSERT INTO Statement:INSERT INTO table_name VALUES (value1,value2,value3,…);
SQLデータ取得:SELECT col_name1, col_name2, … FROM db_name.tbl_name;
SQL GROUP BY Statement:The GROUP BY statement is used in conjunction with the aggregate functions to group the result-set by one or more columns.
user agent:is software (a software agent) that is acting on behalf of a user.
index.php
<?php require_once(__DIR__ . '/config.php'); require_once(__DIR__ . '/Poll.php'); try { $poll = new \MyApp\Poll(); } catch (Exception $e){ echo $e->getMessage(); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST'){ $poll->post(); } $err = $poll->getError(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Poll</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> </head> <body> <?php if (isset($err)) : ?> <div class="error"><?= h($err); ?></div> <?php endif; ?> <h1>Which do you like best?</h1> <form action="" method="post"> <div class="row"> <div class="box" id="box_0" data-id="0"></div> <div class="box" id="box_1" data-id="1"></div> <div class="box" id="box_2" data-id="2"></div> <input type="hidden" id="answer" name="answer" value=""> <input type="hidden" name="token" value="<?= h($_SESSION['token']); ?>"> </div> <div id="btn">Vote and See Results</div> </form> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> $(function(){ 'use strict'; $('.box').on('click', function(){ $('.box').removeClass('selected'); $(this).addClass('selected'); $('#answer').val($(this).data('id')); }); $('#btn').on('click', function(){ if ($('#answer').val() === ''){ alert('Choose one!'); } else { $('form').submit(); } }); $('.error').fadeOut(3000); }); </script> </body> </html>
Poll.php
<?php namespace MyApp; class Poll{ private $_db; public function __construct(){ $this->_connectDB(); $this->_createToken(); } private function _createToken(){ if(!isset($_SESSION['token'])){ $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16)); } } private function _validateToken(){ if( !isset($_SESSION['token']) || !isset($_POST['token']) || $_SESSION['token'] !== $_POST['token'] ){ throw new \Exception('invalid token!'); } } public function post(){ try { $this->_validateToken(); $this->_validateAnswer(); $this->_save(); //redirect to result.php header('Location: http://' . $_SERVER['HTTP_HOST'] . '/result.php'); } catch(\Exception $e){ // set error $_SESSION['err'] = $e->getMessage(); // ridirect to index.php header('Location: http://' . $_SERVER['HTTP_HOST']); } exit; } public function getResults(){ $data = array_fill(0, 3, 0); $sql = "select answer, count(id) as c from answers group by answer"; foreach ($this->_db->query($sql) as $row){ $data[$row['answer']] = (int)$row['c']; } return $data; } public function getError(){ $err = null; if (isset($_SESSION['err'])){ $err = $_SESSION['err']; unset($_SESSION['err']); } return $err; } private function _validateAnswer(){ // var_dump($_POST); // exit; if ( !isset($_POST['answer']) || !in_array($_POST['answer'], [0, 1, 2]) ){ throw new \Exception('invalid answer!'); } } private function _save(){ $sql = "insert into answers (answer, created, remote_addr, user_agent, answer_date) values (:answer, now(), :remote_addr, :user_agent, now())"; $stmt = $this->_db->prepare($sql); $stmt->bindValue(':answer', (int)$_POST['answer'], \PDO::PARAM_INT); $stmt->bindValue(':remote_addr', $_SERVER['REMOTE_ADDR'], \PDO::PARAM_STR); $stmt->bindValue(':user_agent', $_SERVER['HTTP_USER_AGENT'], \PDO::PARAM_STR); try { $stmt->execute(); } catch(\PDOException $e){ throw new \Exception('No more vote for today!'); } // exit; } private function _connectDB(){ try { $this->_db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD); $this->_db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); } catch(\PDOException $e){ throw new \Exception('Failed to connect DB'); } } }
result.php
<?php require_once(__DIR__ . '/config.php'); require_once(__DIR__ . '/Poll.php'); try { $poll = new \MyApp\Poll(); } catch (Exception $e){ echo $e->getMessage(); exit; } $results = $poll->getResults(); // var_dump($results); // exit; // $results = [ // 0 => 12, // 1 => 32, // 2 => 44 // ]; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Poll Result</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>Result ...</h1> <div class="row"> <?php for($i = 0; $i < 3; $i++) : ?> <div class="box" id="box_<?= h($i); ?>"><?= h($results[$i]); ?></div> <?php endfor; ?> </div> <a href="/"><div id="btn">Go Back</div></a> </body> </html>
styles.css
body { font-size: 16px; font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 0; } h1 { font-size: 22px; margin: 30px 0; } .row { margin-bottom: 15px; } .box { width: 150px; height: 150px; cursor: pointer; display: inline-block; opacity: 0.5; color: #fff; font-size: 48px; font-weight: bold; line-height: 150px; } .box + .box { margin-left: 10px; } #box_0 { background: url('photo_0.jpg'); } #box_1 { background: url('photo_1.jpg'); } #box_2 { background: url('photo_2.jpg'); } .selected { opacity: 1.0; } #btn { display: inline-block; width: 150px; padding: 7px; font-size: 14px; cursor: pointer; border-radius: 5px; background: #00aaff; box-shadow: 0 4px 0 #0088cc; color: #fff; } #btn:hover{ opacity: 0.8; } .error{ background: orange; padding: 7px; color: #fff; }
mySQL
create database poll_php; grant all on poll_php.* to dbuser@localhost identified by 'xxxx'; use poll_php create table answers ( id int not null auto_increment primary key, answer int not null, created datetime, remote_addr varchar(15), user_agent varchar(255), answer_date date, unique unique_answer(remote_addr, user_agent, answer_date) );
クイズアプリ
予め正しい答えを全て配列の0に入れておき、click functionで正しいか正誤判定しています。選択肢はシャッフルして表示し、最後に、正解率を表示させています。
reference
Autoloading Classes:The spl_autoload_register() function registers any number of autoloaders, enabling for classes and interfaces to be automatically loaded if they are currently not defined. By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error.
index.php
<?php require_once(__DIR__ . '/config.php'); $quiz = new MyApp\Quiz(); if(!$quiz->isFinished()) { $data = $quiz->getCurrentQuiz(); shuffle($data['a']); } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Intractive Art</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> </head> <body> <?php if ($quiz->isFinished()) : ?> <div id="container"> <div id="result"> your score ... <div><?= h($quiz->getScore()); ?>%</div> </div> <a href=""><div id="btn">Replay</div></a> </div> <?php $quiz->reset(); ?> <?php else : ?> <div id="container"> <h1>Q. <?= h($data['q']); ?></h1> <ul> <?php foreach ($data['a'] as $a) : ?> <li class="answer"><?= h($a); ?></li> <!-- <li class="answer">A1</li> <li class="answer">A2</li> <li class="answer">A3</li> --> <?php endforeach; ?> </ul> <div id="btn" class="disabled"><?= $quiz->isLast() ? 'Show Result' : 'Next Question'; ?></div> <input type="hidden" id="token" value="<?= h($_SESSION['token']); ?>"> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="quiz.js"></script> <?php endif; ?> </body> </html>
autoload.php
<?php spl_autoload_register(function($class){ $prefix = 'MyApp\\'; if (strpos($class, $prefix) === 0){ $className = substr($class, strlen($prefix)); $classFilePath = __DIR__ . '/' . $className . '.php'; if (file_exists($classFilePath)){ require $classFilePath; } else { echo 'No such class' . $className; exit; } } }); [/php] _answer.php [php] <?php require_once(__DIR__ . '/config.php'); $quiz = new MyApp\Quiz(); try{ $correctAnswer = $quiz->checkAnswer(); } catch (Exception $e) { header($_SERVER['SERVER_PROTOCOL']. ' 403 Forbidden', true, 403); echo $e->getMessage(); exit; } header('Content-Type: application/json; charset=UTF-8'); echo json_encode([ 'correct_answer' => $correctAnswer ]);
Token.php
<?php require_once(__DIR__ . '/config.php'); $quiz = new MyApp\Quiz(); try{ $correctAnswer = $quiz->checkAnswer(); } catch (Exception $e) { header($_SERVER['SERVER_PROTOCOL']. ' 403 Forbidden', true, 403); echo $e->getMessage(); exit; } header('Content-Type: application/json; charset=UTF-8'); echo json_encode([ 'correct_answer' => $correctAnswer ]);
Quiz.php
<?php namespace MyApp; class Quiz{ private $_quizSet = []; public function __construct(){ $this->_setup(); Token::create(); if(!isset($_SESSION['current_num'])){ $this->_initSession(); } } public function checkAnswer(){ Token::validate('token'); $correctAnswer = $this->_quizSet[$_SESSION['current_num']]['a'][0]; if (!isset($_POST['answer'])){ throw new \Exception('answer not set!'); } if($correctAnswer === $_POST['answer']){ $_SESSION['correct_count']++; } $_SESSION['current_num']++; return $correctAnswer; } public function isFinished(){ return count($this->_quizSet) === $_SESSION['current_num']; } public function getScore() { return round($_SESSION['correct_count'] / count($this->_quizSet) * 100); } public function isLast(){ return count($this->_quizSet) === $_SESSION['current_num'] + 1; } public function reset(){ $this->_initSession(); // $_SESSION['current_num'] = 0; // $_SESSION['correct_count'] = 0; } private function _initSession(){ $_SESSION['current_num'] = 0; $_SESSION['correct_count'] = 0; } public function getCurrentQuiz() { return $this->_quizSet[$_SESSION['current_num']]; } private function _setup(){ $this->_quizSet[] = [ 'q' => '1543年は、ある物が日本に伝えられた年でもある。それは何か?', 'a' => ['鉄砲', 'キリスト教', '貿易', '忍法'] ]; $this->_quizSet[] = [ 'q' => '海上交通の要地に作られた港町で有名なのはどこ?', 'a' => ['堺', '伊丹', '京都', '江戸'] ]; $this->_quizSet[] = [ 'q' => '1639年に鎖国は完成する。この年から、来航を禁止された国はどこ?', 'a' => ['ポルトガル', 'イギリス', '清', 'オランダ'] ]; } }
config.php
quiz.js
$(function() { 'use strict'; $('.answer').on('click', function() { var $selected = $(this); if ($selected.hasClass('correct') || $selected.hasClass('wrong')) { return; } $selected.addClass('selected'); var answer = $selected.text(); $.post('/_answer.php', { answer: answer, token: $('#token').val() }).done(function(res) { $('.answer').each(function() { if ($(this).text() === res.correct_answer) { $(this).addClass('correct'); } else { $(this).addClass('wrong'); } }); // alert(res.correct_answer); if (answer === res.correct_answer) { // correct! $selected.text(answer + ' ... CORRECT!'); } else { // wrong! $selected.text(answer + ' ... WRONG!'); } $('#btn').removeClass('disabled'); }); }); $('#btn').on('click', function() { if (!$(this).hasClass('disabled')) { location.reload(); } }); });
body { font-size: 16px; font-family: Arial, sans-serif; } #container { width: 500px; margin: 15px auto; } h1, ul > li { border: 1px solid #ddd; border-radius: 5px; } h1 { padding: 10px; height: 50px; font-size: 18px; margin: 0 0 10px; } ul { list-style: none; margin: 0 0 10px; padding: 0; } ul > li { margin-bottom: 7px; padding: 7px 10px; cursor: pointer; } #btn { text-align: center; float: right; width: 100px; padding: 7px; color: #fff; border-radius: 5px; background: #00aaff; box-shadow: 0 4px 0 #0088cc; cursor: pointer; font-size: 14px; } #btn.disabled { opacity: 0.5; } .correct{ color: limegreen; font-weight: bold; } .wrong { color: #ddd; } .selected { font-weight: bold; } #result { border: 1px solid #ddd; border-radius: 5px; margin-bottom: 15px; text-align: center; padding: 30px 0 50px; } #result > div { font-size: 64px; font-weight: bold; margin-top: 30px; }
todo app
mysqlと連携したtodoアプリです。削除に際して、チェックボックスはajaxを使っています。
reference
openssl_random_pseudo_bytes:Generate a pseudo-random string of bytes
<?php session_start(); require_once(__DIR__ . '/config.php'); require_once(__DIR__ . '/functions.php'); require_once(__DIR__ . '/Todo.php'); // get todos $todoApp = new \MyApp\Todo(); $todos = $todoApp->getAll(); //var_dump($todos); //exit; // create table todos( // id int not null auto_increment primary key, // state tinyint(1) default 0, // title text // ); // // insert into todos (state, title) values // (0, 'todo 0'), // (0, 'todo 1'), // (1, 'todo 2'); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Todo app</title> <link rel="stylesheet" href="styles.css"> <style> </style> </head> <body> <div id="container"> <h1>Todos</h1> <form action="" id="new_todo_form"> <input type="text" id="new_todo" placeholder="What needs to be done?"> </form> <ul id="todos"> <?php foreach ($todos as $todo) : ?> <li id="todo_<?= h($todo->id); ?>" data-id="<?= h($todo->id); ?>"> <input type="checkbox" class="update_todo" <?php if ($todo->state === '1') { echo 'checked'; } ?>> <span class="todo_title <?php if ($todo->state === '1') { echo 'done'; } ?>"><?= h($todo->title); ?></span> <div class="delete_todo">x</div> </li> <?php endforeach; ?> <li id="todo_template" data-id=""> <input type="checkbox" class="update_todo"> <span class="todo_title"></span> <div class="delete_todo">x</div> </li> </ul> </div> <input type="hidden" id="token" value="<?= h($_SESSION['token']); ?>"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> <script src="todo.js"></script> </body> </html>
$(function() { 'use strict'; $('#new_todo').focus(); // update $('#todos').on('click', '.update_todo', function() { // idを取得 var id = $(this).parents('li').data('id'); // ajax処理 $.post('_ajax.php', { id: id, mode: 'update', token: $('#token').val() }, function(res) { if (res.state === '1') { $('#todo_' + id).find('.todo_title').addClass('done'); } else { $('#todo_' + id).find('.todo_title').removeClass('done'); } }) }); // delete $('#todos').on('click', '.delete_todo', function() { // idを取得 var id = $(this).parents('li').data('id'); // ajax処理 if (confirm('are you sure?')){ $.post('_ajax.php', { id: id, mode: 'delete', token: $('#token').val() }, function() { $('#todo_' + id).fadeOut(800); }); } }); // create $('#new_todo_form').on('submit', function() { // titleを取得 var title = $('#new_todo').val(); // ajax処理 $.post('_ajax.php', { title: title, mode: 'create', token: $('#token').val() }, function(res) { // liを追加 var $li = $('#todo_template').clone(); $li .attr('id', 'todo_' + res.id) .data('id', res.id) .find('.todo_title').text(title); $('#todos').prepend($li.fadeIn()); $('#new_todo').val('').focus(); }); return false; }); });
<?php session_start(); require_once(__DIR__ . '/config.php'); require_once(__DIR__ . '/functions.php'); require_once(__DIR__ . '/Todo.php'); $todoApp = new \MyApp\Todo(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { $res = $todoApp->post(); header('Content-Type: application/json'); echo json_encode($res); exit; } catch (Exception $e) { header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500); echo $e->getMessage(); exit; } }
<?php namespace MyApp; class Todo { private $_db; public function __construct() { $this->_createToken(); try { $this->_db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD); $this->_db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); } catch (\PDOException $e) { echo $e->getMessage(); exit; } } private function _createToken(){ if (!isset($_SESSION['token'])){ $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16)); } } public function getAll() { $stmt = $this->_db->query("select * from todos order by id desc"); return $stmt->fetchAll(\PDO::FETCH_OBJ); } public function post() { $this->_validateToken(); if (!isset($_POST['mode'])) { throw new \Exception('mode not set!'); } switch ($_POST['mode']) { case 'update': return $this->_update(); case 'create': return $this->_create(); case 'delete': return $this->_delete(); } } private function _validateToken(){ if ( !isset($_SESSION['token']) || !isset($_POST['token']) || $_SESSION['token'] !== $_POST['token'] ) { throw new \Exception('invalid token!'); } } private function _update() { if (!isset($_POST['id'])) { throw new \Exception('[update] id not set!'); } $this->_db->beginTransaction(); $sql = sprintf("update todos set state = (state + 1) %% 2 where id = %d", $_POST['id']); $stmt = $this->_db->prepare($sql); $stmt->execute(); $sql = sprintf("select state from todos where id = %d", $_POST['id']); $stmt = $this->_db->query($sql); $state = $stmt->fetchColumn(); $this->_db->commit(); return [ 'state' => $state ]; } private function _create() { if (!isset($_POST['title']) || $_POST['title'] === '') { throw new \Exception('[create] title not set!'); } $sql = "insert into todos (title) values (:title)"; $stmt = $this->_db->prepare($sql); $stmt->execute([':title' => $_POST['title']]); return [ 'id' => $this->_db->lastInsertId() ]; } private function _delete() { if (!isset($_POST['id'])) { throw new \Exception('[delete] id not set!'); } $sql = sprintf("delete from todos where id = %d", $_POST['id']); $stmt = $this->_db->prepare($sql); $stmt->execute(); return []; } }
PHP カレンダー
カレンダーにはテーブルの中に、phpのdate関数フォーマットを使います。wはNumeric representation of the day of the weekです。
PHP Date:http://php.net/manual/en/function.date.php
-reference
DatePeriod class:A date period allows iteration over a set of dates and times, recurring at regular intervals, over a given period.
sprintf:Return a formatted string
var_dump: Dumps information about a variable
<?php require 'Calendar.php'; function h($s){ return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); } $cal = new \MyApp\Calendar(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Intractive Art</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> <style> </style> </head> <body> <table> <thead> <tr> <th><a href="/?t=<?php echo h($cal->prev); ?>">«</a></th> <th colspan="5"><a href=""><?php echo h($cal->yearMonth); ?></a></th> <th><a href="/?t=<?php echo h($cal->next); ?>">»</a></th> </tr> </thead> <tbody> <tr> <td>Sun</td> <td>Mon</td> <td>Tue</td> <td>Wed</td> <td>Thu</td> <td>Fri</td> <td>Sat</td> </tr> <?php $cal->show(); ?> </tbody> <tfoot> <tr> <th colspan="7"><a href="/">Today</a></th> </tr> </tfoot> </table> <script> </script> </body> </html>
<?php namespace MyApp; class Calendar { public $prev; public $next; public $yearMonth; private $_thisMonth; public function __construct(){ try { if(!isset($_GET['t']) || !preg_match('/\A\d{4}-\d{2}\z/', $_GET['t'])){ throw new \Exception(); } $this->_thisMonth = new \DateTime($_GET['t']); } catch (\Exception $e){ $this->_thisMonth = new \DateTime('first day of this month'); } $this->prev = $this->_createPrevLink(); $this->next = $this->_createNextLink(); $this->yearMonth = $this->_thisMonth->format('F Y'); } private function _createPrevLink(){ $dt = clone $this->_thisMonth; return $dt->modify('-1 month')->format('Y-m'); } private function _createNextLink(){ $dt = clone $this->_thisMonth; return $dt->modify('+1 month')->format('Y-m'); } public function show() { $tail = $this->_getTail(); $body = $this->_getBody(); $head = $this->_getHead(); $html = '<tr>' . $tail . $body . $head . '</tr>'; echo $html; } private function _getTail(){ $tail = ''; $lastDayOfPrevMonth = new \DateTime('last day of ' . $this->yearMonth . ' -1 month'); while($lastDayOfPrevMonth->format('w') < 6){ $tail = sprintf('<td class="gray">%d</td>', $lastDayOfPrevMonth->format('d')) . $tail; $lastDayOfPrevMonth->sub(new \DateInterval('P1D')); } return $tail; } private function _getBody(){ $body = ''; $period = new \DatePeriod( new \DateTime('first day of' . $this->yearMonth), new \DateInterval('P1D'), new \DateTime('first day of ' . $this->yearMonth . ' +1 month') ); $today = new \DateTime('today'); foreach($period as $day){ if ($day->format('w') === '0') { $body .= '</tr><tr>';} $todayClass = ($day->format('Y-m-d') === $today->format('Y-m-d')) ? 'today' : ''; $body .= sprintf('<td class="youbi_%d %s">%d</td>', $day->format('w'), $todayClass, $day->format('d')); } return $body; } private function _getHead() { $head = ''; $firstDayOfNextMonth = new \DateTime('first day of ' . $this->yearMonth . ' +1 month'); while ($firstDayOfNextMonth->format('w') > 0) { $head .= sprintf('<td class="gray">%d</td>', $firstDayOfNextMonth->format('d')); $firstDayOfNextMonth->add(new \DateInterval('P1D')); } return $head; } } // $yearMonth = $thisMonth->format('F Y');
body { font-family: Arial, sans-serif; font-size: 14px; } a { text-decoration: none; } table { margin: 15px auto; border: 1px solid #ddd; border-collapse: collapse; } th { background: #eee; } th, td { padding: 7px; text-align: center; } .youbi_0{ color: red; } .youbi_6 { color: blue; } .today { font-weight: bold; } .gray { color: #dedede; }
functions, config
<?php function connectDb(){ try { return new PDO(DSN, DB_USER, DB_PASSWORD); } catch (PDOException $e){ echo $e->getMessage(); exit; } } function h($s){ return htmlspecialchars($s, ENT_QUOTES, "UTF-8"); } function setToken(){ if (!isset($_SESSION['token'])){ $_SESSION['token'] = sha1(uniqid(mt_rand(), true)); } } function checkToken(){ if (empty($_POST['token']) || $_POST['token'] != $_SESSION['token']){ echo "不正な処理です!"; exit; } }
/* create database contact_php; grant all on contact_php.* to dbuser@localhost identified by 'xxxx'; use contact_php create table entries ( id int not null auto_increment primary key, name varchar(255), email varchar(255), memo text, created datetime, modified datetime ); alter table entries add status enum('active', 'deleted') default 'active' after memo; */ define('DSN','mysql:host=localhost;dbname=contact_php'); define('DB_USER','dbuser'); define('DB_PASSWORD','xxxx'); define('SITE_URL','http://192.168.33.10:8000'); define('ADMIN_URL', SITE_URL.'/admin/'); error_reporting(E_ALL & ~E_NOTICE); session_set_cookie_params(0, '');
edit, delete
<?php require_once('../config.php'); require_once('../functions.php'); session_start(); $dbh = connectDb(); if (preg_match('/^[1-9][0-9]*$/', $_GET['id'])){ $id = (int)$_GET['id']; } else{ echo "不正なIDです!"; exit; } if ($_SERVER['REQUEST_METHOD'] != "POST"){ setToken(); $stmt = $dbh->prepare("select * from entries where id = :id limit 1"); $stmt->execute(array(":id" => $id)); $entry = $stmt->fetch() or die("no one found!"); $name = $entry['name']; $email = $entry['email']; $memo = $entry['memo']; } else { checkToken(); $name = $_POST['name']; $email = $_POST['email']; $memo = $_POST['memo']; $error = array(); if(!filter_var($email, FILTER_VALIDATE_EMAIL)){ $error['email'] = 'メールアドレスの形式が正しくありません'; } if($email == ''){ $error['email'] = 'メールアドレスを入力してください'; } if($memo == ''){ $error['memo'] = '内容を入力してください'; } if(empty($error)){ $sql = "update entries set name = :name, email = :email, memo = :memo, modified = now() where id = :id"; $stmt = $dbh->prepare($sql); $params = array( ":name" => $name, ":email" => $email, ":memo" => $memo, ":id" => $id ); $stmt->execute($params); header('Location: '.ADMIN_URL); exit; } } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>データの編集</title> </head> <body> <h1>データの編集</h1> <form method="POST" action=""> <p>お名前:<input type="text" name="name" value="<?php echo h($name); ?>"></p> <p>メールアドレス*:<input type="text" name="email" value="<?php echo h($email); ?>"> <?php if($error['email']){ echo h($error['email']); } ?></p> <p>内容*:</p> <p><textarea name="memo" cols="40" rows="5"><?php echo h($memo); ?></textarea> <?php if($error['memo']){ echo h($error['memo']); } ?></p> <p><input type="submit" value="更新"></p> <input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"> </form> <p><a href="<?php echo ADMIN_URL; ?>">戻る</a> </body> </html>
delete
<?php require_once('../config.php'); require_once('../functions.php'); $dbh = connectDb(); $id = (int)$_POST['id']; $dbh->query("update entries set status = 'deleted' where id = $id"); echo $id;
thanks
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>ありがとうございました!</title> </head> <body> <h1>ありがとうございました!</h1> <p></p> <p><a href="index.php">お問い合わせフォームに戻る</a></p> </body> </html>