ゆるキャラのペパクラ情報サイトを改善する(5)削除スクリプトを作る

0
    JUGEMテーマ:ホームページ作成

    それでは最終回は、削除スクリプトypdelete.phpの作成です。
    まずは前回と同様、必要な機能の整理からです。

    ・修正フォームの削除ボタンから呼び出され、パスワードの照合画面を表示をする。併せて修正フォームに戻るリンクも表示する。
    ・自分自身から呼び出されたときは、パスワードを照合し、正しければ削除する。削除が完了したら、ゆるキャラペパクラインデックスのトップに戻るリンクを表示する。

    今回も複数の機能を1つのスクリプトで実現しますので、両者を何らかの形で見分ける必要があります。しかし今回は削除という大切の機能を実現するスクリプトなので、パラメータをGETで送るようなことはしたくありません。修正フォームからindex情報をもって初めて来るときも、パスワードを入力して再度自分を呼び出すときも両方POSTです。そこで、自分で自分を呼び出すときには特別なパラメータを追加することにします。「delete」というパラメータがセットされていたら自分から呼び出された、と判断することにします。すると全体構成はこうなります。
    if(!isset($_POST["delete"])){    
      // パスワードの再入力フォーム表示
    }else{  
      // データベースに接続
      // パスワードチェック
      if($row["password"]==$_POST["password"]){
        //削除処理
      }else{  
        // パスワード間違い→再入力指示
      }
    }
    
    ではこれに従い詳細を詰めてゆきましょう。
    まずはパスワードの再入力フォームです。これはほぼecho文のベタ打ちでいいでしょう。
      echo'<p>本当に消去していいですか?</p>';
      echo'<p>宜しければパスワードを入力して「削除」をクリックしてください</p>';
      echo'<form action="ypdelete.php" method="post">
      <p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>
      <input type="hidden" name="delete" value="delete"/>
      <input type="hidden" name="id" value='.$_POST["id"].' />
      <p><input type="submit" name="submit" value="削除"/></p>
      </form>';
      echo'<p class="backToMod"><a href="http://papercraft.techikun.com/ypmod.php?id='.$_POST["id"].'">修正ページに戻る</a></p>';
    
    6行目と9行目にidを送る部分だけ、$_POSTを参照しています。
    それと、5行目がスペシャルキーワード"delete"を埋め込んでいるところです。
    次はおなじみデータベースに接続し、パスワードを取得するところです。
      $pdo = new PDO(
        'mysql:dbname=LA********-mysql5;host=********.phy.lolipop.lan;charset=utf8',
        'LA********',
        'password',
        array(
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_EMULATE_PREPARES => false,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
        )
      );
      $stmt = $pdo->prepare('SELECT * FROM テーブル名 WHERE `index`=:index');
      $stmt->bindValue(':index', (int)$_POST['id']);
      $stmt->execute();
      $row = $stmt->fetch();
    
    前半はもう説明はいらないでしょう。
    後半も、indexを指定してSELECT文でデータベースからデータを読み出し、$rowに格納しているいつもの流れです。
    これを受けてパスワードチェックのif文を抜けると次が実際の削除処理です。
        $stmt4 = $pdo->prepare('DELETE FROM テーブル名 WHERE `index`=:index');
        $stmt4->bindValue(':index', (int)$_POST['id']);
        $stmt4->execute();
        echo'<p>【削除完了!】</p>';
        echo'<p class="returnToTop"><a href="http://papercraft.techikun.com/ypindex.php">ゆるキャラペパクラインデックスのトップへ戻る</a></p>';
    
    削除はDELETE文で、3行で終了。
    完了表示をしたうえで、トップへ戻るリンクを表示して終了です。
    最後のパスワード間違い時の処理は次の通りです。
        echo'<p>本当に消去していいですか?</p>';
        echo'<p>宜しければパスワードを入力して「削除」をクリックしてください</p>';
        echo'<form action="ypdelete.php" method="post">
        <p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>
        <p class="errorcomment">*正しいパスワードを入力してください。</p>
        <input type="hidden" name="delete" value="delete"/>
        <input type="hidden" name="id" value='.$_POST["id"].' />
        <p><input type="submit" name="submit" value="削除"/></p>
        </form>';
        echo'<p class="backToMod"><a href="http://papercraft.techikun.com/ypmod.php?id='.$_POST["id"].'">修正ページに戻る</a></p>';
    
    最初のブロックに、class="errorcomment"で「正しいパスワードを入力してください」の一文が追加されただけでした。


    以上で今回のPHPでMySqlを操作してデータベースを使ったウェブアプリを作るシリーズは完了です。
    次回作をお楽しみに☆


     


    ゆるキャラのペパクラ情報サイトを改善する(4)データベース修正スクリプトの作成

    0
      JUGEMテーマ:ホームページ作成

      1. ypmod.phpの機能
      まず、データベース修正スクリプトを作成するにあたり、どれだけの機能を実現する必要があるのかを整理してみましょう。
      大きくは次の4つになります。
      (1)新規登録ボタンからのリンクで、新規登録フォームの表示
      (2)一覧表からのリンクで、データベース内容修正フォームの表示
      (3)新規登録フォームからの呼び出しで、新規データの登録
      (4)修正フォームからの呼び出しで、データベース内容の修正
      このうち(3)と(4)には、入力されたデータをチェックして、エラーがある場合は修正を促すというサブ機能も必要です。
      これらの4つの機能を、要求元を見分けて、それぞれに機能を実現してやる必要があります。

      まず、(1)、(2)と(3)、(4)の大きく2つに分類します。これは、前者がリンクからの呼び出しで、後者がフォームからの呼び出しになっているところに注目します。
      何らかのデータをスクリプトに送るには2つの方法があります。GETとPOSTです。
      GETは送りたいデータをパラメータとしてURLにくっつけて送ります。
      <a href="http://papercraft.techikun.com/ypmod.php?id=1>GETによる呼び出し</a>
      
      とこんな感じです。情報量は少ないですが、特別な仕組み無しに簡単にデータを送りつけることができます。
      一方POSTは、内部変数を使ってデータを送りますので、より複雑なデータも送ることができます。入力フォームから送る場合は主にこちらを使います。つまりPOSTで送られているかどうかで(1)、(2)と(3)、(4)を見分けることができるのです。
      具体的には、POSTで送られた場合は、$_SERVER["REQUEST_METHOD"] という変数に "POST"が入れられますので、ここで見分けます。

      次に(3)と(4)、これは登録済みの場合、データベースで一貫番号のindexを与えていますが、新規登録の場合はこれがありません。従ってindex番号を持っている場合はこれをフォームから隠しパラメータ"hidden"で送ってやり、受け側でこの値がセットされているかどうかをチェックすることで見分けてやります。
      送る方はこちら、
      <input type="hidden" name="id" value='.$row["index"].'>
      
      受け側は、
      if($_POST["id"]){・・・
      
      としてやれば見分けることができます。

      次に(1)と(2)の見分け方ですが、最初はGETかただのリンクかで見極めようと思ったのですが、やってみるとただのリンクも$_SERVER["REQUEST_METHOD"] に"GET"と入ってくるようでした。なので方針変更し、こちらもid有無で見分けることにしました。


      2. ypmod.phpの論理構成
      ということで、先ほど決めた見分け方に従い、データベース修正スクリプトypmod.php全体の論理構成を考えてみました。
      // ヘッダー、タイトル、メニュー、サブタイトル等を表示
      // データベースに接続
      if($_SERVER["REQUEST_METHOD"] == "POST"){   // POSTの場合
      if($_POST["id"]){  // id付きの場合=データベースの修正
      // エラーチェック
      // 画像処理
      // 修正登録
      }else{  // id無しの場合=新規登録処理
      // エラーチェック
      // 画像処理
      // 新規登録
      }
      // 共通処理=入力項目にエラーがあった時の、修正フォーム
      }elseif(($_SERVER["REQUEST_METHOD"] == "GET")and(isset($_GET["id"]))){ // GETでid付きの場合
      // データベースの内容を記入済みの修正フォーム表示
      }else{
      // 新規登録フォームを表示
      }
      // データベース接続解除
      
      こんなところでしょうか。


      3. ypmod.phpの作成
      ではいよいよスクリプトを書いていきます。
      まず、ヘッダー類は省略させていただいて、データベースに接続するところから。
      <?php
      $pdo = new PDO(
        'mysql:dbname=LA********-mysql5;host=********.phy.lolipop.lan;charset=utf8',
        'LA********',
        'password',
        array(
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_EMULATE_PREPARES => false,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
        )
      );
      
      これは前回やった通りですね。では次に、データベース修正処理。まずはエラーチェックから。
      if($_SERVER["REQUEST_METHOD"] == "POST"){    // 登録または修正操作後、修正モード
        if($_POST["id"]){
          // データ不備チェック→DB修正
          $errorflg=0;$errorflg1=0;$errorflg2=0;$errorflg3=0;$errorflg4=0;
          if(!$_POST["name"]){$errorflg=1; $errorflg1=1;}
          if(!$_POST["affiliation"]){$errorflg=1; $errorflg3=1;}
          if(!$_POST["password"]){$errorflg=1; $errorflg4=1;}
          // パスワードチェック
          $stmt1 = $pdo->prepare('SELECT * FROM テーブル名 WHERE `index` = :index');
          $stmt1->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
          $stmt1->execute();
          $row1 = $stmt1->fetch();
          if($_POST["password"]<>$row1["password"]){$errorflg=1; $errorflg4=1;}
      
      考え方は、ラジオボタンで強制的に何か一つ選ばされるのではないテキスト入力のアイテムについて、入力が空だったらエラーとしています。その後にパスワードの照合をしています。
      次は画像処理。
          // 写真変更の場合の処理
          if($_FILES["photourl"]["name"]){
            // エラー処理
            if($_FILES["photourl"]["error"]){
              $errorflg=1; $errorflg2=1;
              //exit;
            }
            $path = $_FILES["photourl"]["tmp_name"];
            $imginfo = getimagesize($path);
            switch ($imginfo[2]){
              case 1: $im = imagecreatefromgif($path); break;
              case 2: $im = imagecreatefromjpeg($path); break;
              case 3: $im = imagecreatefrompng($path); break;
              default: // エラー処理
                $errlrflg=1; $errlrflg2=2; break;
            }
            $wratio = $imginfo[0]/120;
            $hratio = $imginfo[1]/80;
            if($wratio>=$hratio){
              $new_width=120;
              $new_height=round($imginfo[1]/$wratio);
            }else{
              $new_width=round($imginfo[0]/$hratio);
              $new_height=80;
            }
            $new_image = imagecreatetruecolor($new_width, $new_height);
            imagecopyresampled($new_image, $im, 0, 0, 0, 0, $new_width, $new_height, $imginfo[0], $imginfo[1]);
            imagejpeg($new_image,$_FILES["photourl"]["tmp_name"],100);
            $photodata = file_get_contents($path);
          }else{
            $stmt4 = $pdo->prepare('SELECT `photo` FROM テーブル名 WHERE `index`=:index');
            $stmt4->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
            $stmt4->execute();
            $row = $stmt4->fetch();
            $photodata = $row["photo"];
          }
      
      これも画像処理の回に説明した通りですね。imagecreatefrom****()で読み込んが画像を、imagecopyresampled()を使い、imagecreatetruecolor()で作った縮小ファイルに落としてやり、一旦保存してからfile_get_contents()で文字列に読み込んでいます。最後のelseブロックは、新しい写真が指定されなかったら、前回の写真を読み出して再度登録に回そう、というブロックになります。そして修正登録はこちら。
          if(!$errorflg){
            $query2 = 'UPDATE テーブル名 SET `photo`=:photo, `name`=:name, `category`=:category, `area`=:area, `affiliation`=:affiliation, ';
            $query2 = $query2.'`url`=:url, `avail`=:avail, `note`=:note, `lastupdate`=cast(now() as datetime) WHERE `index`=:index';
            $stmt2 = $pdo->prepare($query2);
            $stmt2->bindValue(':photo',$photodata, PDO::PARAM_LOB);
            $stmt2->bindValue(':name',$_POST["name"]);
            if($_POST["category"]=="town"){
              $stmt2->bindValue(':category','ご当地');
            }else{
              $stmt2->bindValue(':category','企業・団体');
            }
            $stmt2->bindValue(':area',$_POST["area"]);
            $stmt2->bindValue(':affiliation',$_POST["affiliation"]);
            $stmt2->bindValue(':url',$_POST["url"]);
            if($_POST["avail"]=="dl"){$stmt2->bindValue(':avail','DL');}
            elseif($_POST["avail"]=="sell"){$stmt2->bindValue(':avail','販売');}
            elseif($_POST["avail"]=="haifu"){$stmt2->bindValue(':avail','配布');}
            elseif($_POST["avail"]=="nodl"){$stmt2->bindValue(':avail','DL終了');}
            elseif($_POST["avail"]=="nosell"){$stmt2->bindValue(':avail','販売終了');}
            elseif($_POST["avail"]=="nohaifu"){$stmt2->bindValue(':avail','配布終了');}
            else{$stmt2->bindValue(':avail','非公開');}
            $stmt2->bindValue(':note',$_POST["note"]);
            $stmt2->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
            $stmt2->execute();
          }
      
      データベースの更新にはUPDATEというクエリを発行します。文法は2〜3行目の通りです。SELECTの時と同様に4行目でprepareしてやり、5行目行こうでプレースホルダに値を順次入れていっています。特記としては、最終更新日付をhow()関数を使って取得し、datetimeにキャストしていること、それとパスワードが無い事(パスワードだけは変更できない仕様です)くらいでしょうか。

      新規登録の場合もこれと似ています。
      エラーチェックは、パスワードチェックが無い点以外は修正登録時と同じです。
      画像処理も修正登録時とほとんど同じですが、elseブロックの中身が変わっています。
          if($_FILES["photourl"]["name"]){
            //
      //中略//
      //
          }else{
            $photodata = file_get_contents("./images/ypindex/no-image_ypindex.jpg");
          }
      
      これは、写真が指定されなかったときは、「NO IMAGE」とかかれたjpegファイルを自動的に取り込むようにしたものです。
      そして登録処理。
          if(!$errorflg){
            $query3 = 'INSERT INTO `yuruchara` (`name`, `photo`, `category`, `area`, `affiliation`, `url`, `avail`, `note`, `password`, `checked`, `lastupdate`) ';
            $query3 = $query3.'VALUES(:name, :photo, :category, :area, :affiliation, :url, :avail, :note, :password, 0, cast(now() as datetime))';
            $stmt3 = $pdo->prepare($query3);
      //
      // 中略
      //
            $new_id = $pdo->lastInsertId();
          }
      
      今度はUPDATE文ではなくINSERT文で、データベースに新たな行を追加しています。それから、indexは自動採番なので、登録が終わった後にlastInsertId()メソッドで番号を取り出しています。
      そしてこの後に共通処理、入力ミス・漏れがあった時の訂正フォームです。
        $checked01="";$checked02="";
        if($_POST["category"]=="town"){$checked01="checked";}
        else{$checked02="checked";}
        $checked11="";$checked12="";$checked13="";$checked14="";$checked15="";$checked16="";$checked17="";
        if($_POST["avail"]=="dl"){$checked11="checked";}
        elseif($_POST["avail"]=="sell"   ){$checked12="checked";}
        elseif($_POST["avail"]=="haifu"  ){$checked13="checked";}
        elseif($_POST["avail"]=="nodl"   ){$checked14="checked";}
        elseif($_POST["avail"]=="nosell" ){$checked15="checked";}
        elseif($_POST["avail"]=="nohaifu"){$checked16="checked";}
        else{$checked17="checked";}
        if($errorflg){
          echo'<p>【不足データがあります】</p>';
        }
        echo'
        <form action="ypmod.php" method="post" enctype="multipart/form-data">
        <p>名前:<input type="text" name="name" value="'.$_POST["name"].'" size="20" /></p>';
        if($errorflg1==1){
          echo'<p class="errorcomment">*キャラクター名を入れてください。</p>';
        }
        if($_POST["id"]){
          echo'<p>写真:&nbsp;<img class=ypphoto src=./ypimg.php?id='.$_POST["id"].'>&nbsp;<input type="file" name="photourl" /></p>';
        }elseif($new_id){
          echo'<p>写真:&nbsp;<img class=ypphoto src=./ypimg.php?id='.$new_id.'>&nbsp;<input type="file" name="photourl" /></p>';
        }else{
          echo'<p>写真:<input type="file" name="photourl" /></p>';
        }
        if($errorflg2){
          echo'<p class="errorcomment">*jpeg,png,gifファイルを指定してください</p>';
        }
        echo'
        <p>分類:
        <input type="radio" name="category" value="town" '.$checked01.' />ご当地
        <input type="radio" name="category" value="company" '.$checked02.' />企業・団体ゆるキャラ
        </p>
        <p>所属:<input type="text" name="affiliation" value="'.$_POST["affiliation"].'" size="20" /></p>';
        if($errorflg3==1){
          echo'<p class="errorcomment">*所属団体を入力してください。</p>';
        }
        echo'
        <p>地域:<input type="text" name="area" value="'.$_POST["area"].'" size="20" /></p>';
        if($errorflg5==1){
          echo'<p class="errorcomment">*所在地域を入力してください。</p>';
        }
        echo'
        <p>入手方法:<br/>
        <input type="radio" name="avail" value="dl" '.$checked11.' />無料ダウンロード
        <input type="radio" name="avail" value="sell" '.$checked12.' />販売
        <input type="radio" name="avail" value="haifu" '.$checked13.' />配布
        <br/>
        <input type="radio" name="avail" value="nodl" '.$checked14.' />ダウンロード終了
        <input type="radio" name="avail" value="nosell" '.$checked15.' />販売終了
        <input type="radio" name="avail" value="nohaifu" '.$checked16.' />配布終了
        <br/>
        <input type="radio" name="avail" value="nothing" '.$checked17.' />非公開
        </p>
        <p>url:<input type="text" name="url" value="'.$_POST["url"].'" size="40" /></p>
        <p>コメント:<br/><textarea name="note" rows="4" cols="40" >'.$_POST["note"].'</textarea></p>
        <p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>';
        if($errorflg4==1){
          echo'<p class="errorcomment">*修正用パスワードを入力してください。</p>';
        }elseif($errorflg4==2){
          echo'<p class="errorcomment">*正しいパスワードを入力してください。</p>';
        }
        if($errorflg==1 and !$_POST["id"]){
          echo'<p><input type="submit" name="submit" value="登録"/></p>';
        }else{
          echo'<p><input type="submit" name="submit" value="修正"/></p>';
        }
        if($_POST["id"]){
          echo'<input type="hidden" name="id" value='.$_POST["id"].'>';
        }else{
          echo'<input type="hidden" name="id" value='.$new_id.'>';
        }
      echo'</form>';
        if($_POST["id"] or $new_id){
          echo'<form action="ypdelete.php" method="post">';
          if($_POST["id"]){
            echo'<input type="hidden" name="id" value='.$_POST["id"].'>';
          }else{
            echo'<input type="hidden" name="id" value='.$new_id.'>';
          }
          echo'<p><input type="submit" name="submit" value="削除"/></p></form>';
        }
       
       
        if(!$errorflg){
          echo'<p><a class="clear_and_new" href="ypmod.php">フォームクリア&新規登録<a></p>';
        }
      
      まず1から11行目までのブロックは、ラジオボタンにチェックを入れるための”checked"の設定をしているところです。
      13〜15行目は、入力漏れがあった時に表示させるコメントです。
      17行目からが訂正フォームを表示させる部分ですが、例えば20〜22行目のようにところどころに、エラーコードに応じてコメントを挿入するような文が入っています。class="errorcomment"とし、CSSで赤く色を付けています。
      67〜71行目で、idがPOSTで来ているかどうかを見て初度登録か修正登録かを判別し、フォームの送信ボタンの文字を入れ替えています。
      その後、72〜77行目で、index番号をhiddenで埋め込んでいます。
      79行目から87行目は、見た目は「削除」ボタンしかありませんが、index番号を埋め込んで削除スクリプトypdelete.phpを呼び出すボタンになっています。
      最後の3行は、無事エラーなしに登録完了した場合に表示される、フォームクリア&新規登録ボタンです。何のオプションも無しにypmod.phpを呼び出しています。

      この後は、修正フォームと新規登録フォームの表示です。細かい説明は省略しようと思います。まずは修正フォーム。
       
      }elseif(($_SERVER["REQUEST_METHOD"] == "GET")and(isset($_GET["id"]))){
        // DBから読み出し後、修正フォームを表示
        $stmt1 = $pdo->prepare('SELECT * FROM yuruchara WHERE `index` = :index');
        $stmt1->bindValue(':index', (int)$_GET["id"], PDO::PARAM_INT);
        $stmt1->execute();
        $row = $stmt1->fetch();
        $checked01="";$checked02="";
        if($row["category"]=="ご当地"){$checked01="checked";}
        else{$checked02="checked";}
        $checked11="";$checked12="";$checked13="";$checked14="";$checked15="";$checked16="";$checked17="";
        if($row["avail"]=="DL"){$checked11="checked";}
        elseif($row["avail"]=="販売"   ){$checked12="checked";}
        elseif($row["avail"]=="配布"  ){$checked13="checked";}
        elseif($row["avail"]=="DL終了"   ){$checked14="checked";}
        elseif($row["avail"]=="販売終了" ){$checked15="checked";}
        elseif($row["avail"]=="配布終了"){$checked16="checked";}
        else{$checked17="checked";}
        echo '<p>【データ修正】</p>
        <form action="ypmod.php" method="post" enctype="multipart/form-data">
        <p>名前:<input type="text" name="name" value="'.$row["name"].'" size="20" />&nbsp;ゆるキャラの名前</p>';
        echo'<p>写真:&nbsp;<img class=ypphoto src=./ypimg.php?id='.$row['index'].'>&nbsp;<input type="file" name="photourl" /><br/>
        &nbsp;&nbsp;&nbsp;&nbsp;(写真は自動的に120×80ピクセルに縮小されます。)</p>';
        echo'
        <p>分類:
        <input type="radio" name="category" value="town" '.$checked01.' />ご当地
        <input type="radio" name="category" value="company" '.$checked02.' />企業・団体ゆるキャラ
        </p>
        <p>所属:<input type="text" name="affiliation" value="'.$row["affiliation"].'" size="20" />&nbsp;所属する市町村・企業・団体名</p>
        <p>地域:<input type="text" name="area" value="'.$row["area"].'" size="20" />&nbsp;都道府県、または全国</p>';
        echo'
        <p>入手方法:<br/>
        <input type="radio" name="avail" value="dl" '.$checked11.' />無料ダウンロード
        <input type="radio" name="avail" value="sell" '.$checked12.' />販売
        <input type="radio" name="avail" value="haifu" '.$checked13.' />配布
        <br/>
        <input type="radio" name="avail" value="nodl" '.$checked14.' />ダウンロード終了
        <input type="radio" name="avail" value="nosell" '.$checked15.' />販売終了
        <input type="radio" name="avail" value="nohaifu" '.$checked16.' />配布終了
        <br/>
        <input type="radio" name="avail" value="nothing" '.$checked17.' />非公開
        </p>
        <p>url:<input type="text" name="url" value="'.$row["url"].'" size="60" /></p>
        <p>コメント:<br/><textarea name="note" rows="4" cols="40" >'.$row["note"].'</textarea></p>
        <p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>';
        echo'<input type="hidden" name="id" value='.$row["index"].'>';
        echo'<p><input type="submit" name="submit" value="修正"/></p>';
        echo'</form>';
        echo'<form action="ypdelete.php" method="post">
        <input type="hidden" name="id" value='.$row["index"].'>
        <p><input type="submit" name="submit" value="削除"/></p>
        </form>';
      
      データベース内の登録情報があらかじめフォームに記入されるようにしています。
      そして新規登録フォームです。
       
      }else{  
          // 新規登録フォームを表示
        echo '<p>【新規追加】</p>
        <form action="ypmod.php" method="post" enctype="multipart/form-data">
        <p>名前:<input type="text" name="name" size="20" />&nbsp;ゆるキャラの名前</p>
        <p>写真:<input type="file" name="photourl" /><br/>
        &nbsp;&nbsp;&nbsp;&nbsp;(写真は自動的に120×80ピクセルに縮小されます。)</p>
        <p>分類:
        <input type="radio" name="category" value="town" checked="checked" />ご当地
        <input type="radio" name="category" value="company" />企業・団体ゆるキャラ
        </p>
        <p>所属:<input type="text" name="affiliation" size="20" />&nbsp;所属する市町村・企業・団体名</p>
        <p>地域:<input type="text" name="area" size="20" />&nbsp;都道府県、または全国</p>
        <p>入手方法:<br/>
        <input type="radio" name="avail" value="dl" checked="checked" />無料ダウンロード
        <input type="radio" name="avail" value="sell" />販売
        <input type="radio" name="avail" value="haifu" />配布
        <br/>
        <input type="radio" name="avail" value="nodl" />ダウンロード終了
        <input type="radio" name="avail" value="nosell" />販売終了
        <input type="radio" name="avail" value="nohaifu" />配布終了
        <br/>
        <input type="radio" name="avail" value="nothing" />非公開
        </p>
        <p>url:<input type="text" name="url" size="60" /></p>
        <p>コメント:<br/><textarea name="note" rows="4" cols="40"></textarea></p>
        <p>修正用パスワード:<input type="password" name="password" value="" size="20"/></p>
        <p><input type="submit" name="submit" value="登録"/></p>
        </form>';
      }
      
      何も書かれていない、まっさらのフォームです。
      最後に告知をして、接続を切って終了です。
      echo '<p>本インデックスへのご意見・ご要望・データ削除依頼などは→<a href="http://6243.teacup.com/papercraft/bbs" target="_blank">【掲示板】</a>へどうぞ。</p>';
      $pdo = null;
      


      以上、長くなりましたがデータベース修正スクリプトの説明でした。
      次回は最終回、データベース内容削除スクリプトのypdelete.phpの解説です。
       


      ゆるキャラのペパクラ情報サイトを改善する(3)画像をアップロードする

      0
        JUGEMテーマ:ホームページ作成

        えーと今回は、予告から順番を入れ替えて、先に画像登録処理について解説することにします。

        1.画像のアップロード&受け取り方
        まず画像のアップロードですが、これはフォームの「file」を使用します。
        <form action="ypmod.php" method="post" enctype="multipart/form-data">
        <p>写真:<input type="file" name="photodata" /><br/>
        &nbsp;&nbsp;&nbsp;&nbsp;(写真は自動的に120×80ピクセルに縮小されます。)</p>
        
        とこんな感じです。ポイントは1行目でenctype="multipart/form-data"を指定するところです。これで

        こんな感じのフォームが表示され、「参照」をクリックするとアップロードしたいファイルを指定できます。
        ここでファイルを指定してフォームをPOSTで送信すると、ファイルがテンポラリーフォルダに置かれ、$_FILESという変数にファイルの情報が入力されて送信されます。その中身は、
        $_FILES["photodata"]["name"]:ファイル名
        $_FILES["photodata"]["type"]:ファイルの種類(image/jpg等)
        $_FILES["photodata"]["tmp_name"]:仮置き場所のパス
        $_FILES["photodata"]["error"]:エラー有無
        $_FILES["photodata"]["size"]:ファイルサイズ
        
        となっています。これを受け取るだけでしたら、
        $path=$_FILES["photodata"]["tmp_name"];
        $photodata=file_get_contents($path);
        
        で受け取ることができます。


        2.画像の縮小方法
        フォームから送られたデータを、規定のサイズに縮小します。今回は検索結果の一覧表に表示されるサムネール画像ですので、120×80の大きさに縮小したいと思います。
        縮小には2つの種類があります。

        (1)短い方に合わせる
        120×80ですから3:2の比になりますが、これより比の小さい方に合わせて長すぎる方はトリミングする、という方法です。ブログの記事一覧などでアイキャッチ画像の一部を表示させて目を引きたいような場合に良く使われますが、これはクリックすれば全体の画像が見えるようになっているのが前提だと思います。

        (2)長い方に合わせる
        逆に3:2の比より長い方にあわせて縮小する。例えば300×300の画像などは80×80に縮小して、120×80の枠をはみ出ないようにする。画像の形がばらばらになってしまいますが、画像が切り取られてしまうことはありません。

        今回は後者で行こうと思います。
        では早速コードを。
        $path = $_FILES["photourl"]["tmp_name"];
        $imginfo = getimagesize($path);
        switch ($imginfo[2]){
          case 1: $im = imagecreatefromgif($path); break;
          case 2: $im = imagecreatefromjpeg($path); break;
          case 3: $im = imagecreatefrompng($path); break;
          default: // エラー処理
            $errlrflg=1; $errlrflg2=2; break;
        }
        $wratio = $imginfo[0]/120;
        $hratio = $imginfo[1]/80;
        if($wratio>=$hratio){
          $new_width=120;
          $new_height=round($imginfo[1]/$wratio);
        }else{
          $new_width=round($imginfo[0]/$hratio);
          $new_height=80;
        }
        $new_image = imagecreatetruecolor($new_width, $new_height);
        imagecopyresampled($new_image, $im, 0, 0, 0, 0, $new_width, $new_height, $imginfo[0], $imginfo[1]);
        imagejpeg($new_image,$_FILES["photourl"]["tmp_name"],100);
        $photodata = file_get_contents($path);
        
        1行目で、先ほどの例の通り、パスを取得しています。
        2行目で、今度は画像ファイルの情報を取得します。内容は
         $imginfo[0]:画像の幅
         $imginfo[1]:画像の高さ
         $imginfo[2]:画像の種類、1:gif, 2:jpeg, 3:png
        となっています。
        4〜6行目でこの画像の種類に応じて、imagecreatefrom***関数で画像リソースを作成しています。
        10〜18行目では、画像の縦横の比をチェックして、120×80に収まるような縦横の長さを設定しています。
        19行目で、この新たなサイズの空の画像をまず作ります。
        20行目で、元の画像をサンプリングして新しい画像にはめ込んでやります。
        21行目は、作成した画像をjpeg形式で一旦テンポラリーファイルに落とします。
        そして最後にこのファイルを文字列に読み込んでいます。


        3.画像の形式変換方法
        この手法を応用すると、4行目の、imagecreatefromjpeg(png,gif)で画像リソースを作成し、これをセーブするときに21行目のようにimagejpeg(png)とすることで自在に画像の形式変更が可能です。


        4.画像のデータベースへの登録方法
        画像をデータベースに登録する場合、次の手順になります。
        (1)準備:データベースに「BLOB」形式のカラムを準備しておく。
        (2)画像ファイルを、file_get_contents()関数で文字列に読み込む。
        (3)queryのひな型をprepareして置き、
        (4)文字列に読み込んだ画像ファイルをバインド。
        $stmt->bindValue(':photo',$photodata, PDO::PARAM_LOB);

        これでOKです。


        今回はここまで。次回は本命のデータベース修正スクリプトを作成していきます。

        (4)DB修正スクリプトの作成
        ・ypmod.phpの内部構成
        ・ypmod.phpの作成
        (5)削除スクリプトの作成
        ・ypdelete.phpの作成

         


        ゆるキャラのペパクラ情報サイトを改善する(2)SQLインジェクション対策をする

        0
          JUGEMテーマ:ホームページ作成

          1.SQLインジェクションとは
          さて唐突に始まりました第2話、SQLインジェクションなる言葉がいきなり出てきましたが、これは一体なんでしょう?
          まずSQLとは、Sequential Query Lauguageの略で、言ってしまえばデータベースを操作するコマンドの事です。そこにインジェクションが付きます。インジェクションとは辞書で調べると、注入とか注射とか。併せるとSQLのコマンドに何かが注入されてしまうということになります。何かとはデータベースを操作する別のコマンドです。実際の例を見てみましょう。
          $gid  = $_GET['gid'];
          $sort = $_GET['sort'];
          $sql = "SELECT * FROM users WHERE gid=$gid ORDER BY $sort";
          $result = mysql_query($sql);
          
          これはA Day in Serenity(Reloaded)さんが公開しているサンプルを少し修正したものです。
          意図は恐らく、同じグループIDの人を抽出して、指定した順序で並べ替えるというものだと思います。
          でも、このgidとsort、ユーザーが自由に入力できるようになっていると、何が入ってくるかわかりません。
          例えば、悪意あるユーザがこんな入れ方をしたとします。
          gid=1
          sort=name; delete from users
          
          すると組み合わさってできるクエリはこうなります。
          SELECT * FROM users WHERE gid=1 ORDER BY name; delete from users
          
          これでグループID=1の人のデータは全てデータベースから消去されてしまいます。続けてgidを変えてゆけばデータベース全削除です。これがSQLインジェクションの恐ろしさです。
          私のゆるキャラペパクラインデックスなどは、いたずらで消されてしまったら私がしょんぼりするだけですが、人とやり方よってはデータベースの中身が逆に全部抜き取られ、個人情報の漏洩といったことにもなりかねません。これは穏やかではありません。

          この機会に、SQLインジェクションを受け付けないような対策を施してやろう、と考えたと言う訳なのです。


          2.プリペアドステートメントとプレースホルダとは
          SQLインジェクション対策として最も基本的なのが、「プリペアドステートメント」と「プレースホルダ」を使う方法です。
          プリペアドステートメントとは、SQLを文字列の結合で作ったりせずに、あらかじめひな型として準備しておく機能の事、プレースホルダとはそのひな型の中で、ユーザに指定してほしい部分に仮置きしておく枠のようなものです。

          先ほどの例をプリペアドステートメントとプレースホルダを使って書き換えてみましょう。
          $query = "SELECT * FROM users WHERE gid=:gid ORDER BY :sort";
          $stmt = $pdo->prepare($query);
          $stmt->bindValue(':gid', (int)$_GET["gid"], PDO::PARAM_INT);
          $stmt->bindValue(':sort', $_GET["sort"]);
          
          1行目がクエリのひな型で、中にある「:gid」と「:sort」がプレースホルダです。
          2行目でこれをプリペア=準備しています。
          そして3行目と4行目で、プレースホルダに値を埋め込んでいます。こうすることで、gidやsortはクエリの中の各所に相当するパラメータとして認識されますので、変なコマンドを入れてもコマンドとして認識されなくなるので、安全にクエリを発行できるようになるのです。


          3.PDOとは
          ところで、先ほどの例、見慣れないコマンドが出てきたと思います。これはPDOという仕組みを利用した書き方になっているのですがこのPDOとはなんでしょう?

          PDOは「PHP Data Object」の略で、PHPでデータベースに接続するためのクラスです。クラスとは、おおざっぱに言うと、データを取り込む変数たちとそれを操作するコマンドがセットになったようなものです。併せると、PDOはデータベースに接続するために必要な情報を入れる箱と、データベース接続にかかわる種々の手続き・関数・コマンド等がセットになった便利な道具と思ってもらえればいいでしょう。
          クラスの概念が腑に落ちないという人は、こちらのサイトに一から解説してありますので、こちらをご覧いただくといいと思います。
          【PHP超入門】クラス〜例外処理〜PDOの基礎

          まあつまり、PDOにはデータベースと安全に接続するための機能・手続きがまとまっていますので、mysql関数は止めてPDOでデータベースとの接続周りを書き換えてやろうということなわけです。先ほどのプリペアドステートメントもこのPDOで実現できる機能の一つです。


          4.PDOの使い方
          それではPDOを使ってデータベースにアクセスする手順を追ってみましょう。
          まずは、データベースとの接続です。こうなります。
          $pdo = new PDO(
            'mysql:dbname=LA********-mysql5;host=********.phy.lolipop.lan;charset=utf8',
            'LA********',
            'password',
            array(
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
              PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
              PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
            )
          );
          
          1行目:PDOというクラスのひな型から新しい接続「$pdo」を作りなさい、という宣言になります。
          2行目:接続先のデータベース名、ホスト名、文字コードを指定します。
          3行目:ユーザIDです。
          4行目:パスワードです。もちろんダミーです。
          5〜10行目:オプションを色々設定しています。
          ・PDO::ATTR_ERRMODE:SQL実行時にエラーが起きた際の処置。上記は例外をスローしてくれる設定です。
          ・PDO::ATTR_EMULATE_PREPARES:エミュレーション有無の設定。上記はエミュレーションoff。
          ・PDO::ATTR_DEFAULT_FETCH_MODE:カラム名をキーにした連想記憶配列でデータを取得する設定。
          ・PDO::MYSQL_ATTR_USE_BUFFERED_QUERY:バッファクエリを使用する設定。

          詳しくはQiitaさんに記事がありましたので、そちらもご参照ください。
          PHPでデータベースに接続するときのまとめ

          データベースと接続したら、次はクエリの発行です。
           
          $stmt1 = $pdo->prepare('SELECT * FROM table名 WHERE `index` = :index');
          $stmt1->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
          $stmt1->execute();
          $row1 = $stmt1->fetch();
          if($_POST["password"]<>$row1["password"]){$errorflg=1; $errorflg4=1;}
          

          これは、パスワードチェックを行っている部分のサンプルです。
          1行目:先ほど出てきたprepareの指示です。「->」はクラスがもっている機能「メソッド」を呼び出すときの記号です。
          2行目:プレースホルダに値をバインドしています。
          3行目:クエリを実行するコマンドです。
          4行目:クエリの結果を受け取っています。先ほどの接続オプションで連想記憶配列を指定しましたので、次の5行目ではカラム名をキーにしてパスワードの値を読み出しています。

          同じデータベースに別のクエリを発行したいときは、$pdoはそのまま使い、$stmtの方を色々書き換えてやればOKです。

          最後にすべて終わって接続を切るときは、次のように書きます。
          $pdo = null;
          


          4.ypindex.phpの改修
          それではいよいよ実際のコードを修正していきます。今回は、前に作った、データベースを検索して結果を表にして表示するスクリプト「ypindex.php」を修正していきます。
          まずmysql関数を使った旧コードがこちら。
          $link = mysql_connect('********.phy.lolipop.lan', 'LA********', 'password');
          $db_selected = mysql_select_db('LA********-mysql5', $link);
          $charaset = mysql_query('SET NAMES utf8', $link );
          $query1 = 'SELECT * FROM テーブル名';
          $query1 = $query1.' WHERE name LIKE ¥'%'.$searchword.'%¥'';
          $query1 = $query1.' or area LIKE ¥'%'.$searchword.'%¥'';
          $query1 = $query1.' or affiliation LIKE ¥'%'.$searchword.'%¥'';
          $query1 = $query1.' or note LIKE ¥'%'.$searchword.'%¥'';
          $result1 = mysql_query($query1);
          $numRow1 = mysql_num_rows($result1);
          $itemPerPage = 20;
          $numPage = ceil($numRow1/$itemPerPage);
          
          今見ると恐ろしい書き方をしていますね。ではPDOを使った新コードがこちら。
          $pdo = new PDO(
          'mysql:dbname=LA********-mysql5;host=********.phy.lolipop.lan;charset=utf8',
          'LA********',
          'password',
          array(
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_EMULATE_PREPARES => false,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
          )
          );
          $stmt1 = $pdo->prepare('SELECT * FROM テーブル名 WHERE name LIKE :name or area LIKE :area or affiliation LIKE :affiliation or note LIKE :note');
          $stmt1->bindValue(':name', '%'.$searchword.'%');
          $stmt1->bindValue(':area', '%'.$searchword.'%');
          $stmt1->bindValue(':affiliation', '%'.$searchword.'%');
          $stmt1->bindValue(':note', '%'.$searchword.'%');
          $stmt1->execute();
          $numRow1 = $stmt1->rowCount();
          $itemPerPage = 20;
          $numPage = ceil($numRow1/$itemPerPage);
          
          新しく出てきたのはrowCount()というメソッドです。単に行数を数えているだけです。一旦全体の行数を取得してから、これでページナビゲーションを作ったうえで、指定した部分の20行を呼び出すようにしています。その部分の新コードがこちら。
          $startLine = ($page-1)*20;
          $stmt = $pdo->prepare('SELECT * FROM テーブル名 WHERE name LIKE :name or area LIKE :area or affiliation LIKE :affiliation or note LIKE :note LIMIT :startLine ,20');
          $stmt->bindValue(':name', '%'.$searchword.'%');
          $stmt->bindValue(':area', '%'.$searchword.'%');
          $stmt->bindValue(':affiliation', '%'.$searchword.'%');
          $stmt->bindValue(':note', '%'.$searchword.'%');
          $stmt->bindValue(':startLine', (int)$startLine, PDO::PARAM_INT);
          $stmt->execute();
          (中略)
          while ($row = $stmt->fetch()){
          
          最後のwhile文で1行ずつ取り出して表示させています。そして最後に、
          $pdo = null;
          
          で終了です。


          今回はここまで。次回は本命のデータベース修正スクリプトの作成です。

          (3)DB修正スクリプトの作成
          ・ypmod.phpの内部構成
          ・ypmod.phpの作成
          (4)画像登録処理
          ・画像の受け取り方
          ・画像の縮小方法
          ・画像の形式変換方法
          (5)削除スクリプトの作成
          ・ypdelete.phpの作成

           


          ゆるキャラのペパクラ情報サイトを改善する(1)まずは何をやりたいか

          0
            JUGEMテーマ:ホームページ作成

            1.必要な要件をリストアップすること
            約1年前に立ち上げた、全国のゆるキャラのペーパークラフト情報を集めた「ゆるキャラペパクラインデックス」ですが、色々不満も出てきていますので、ここらで思い切って改善を図りたい、というのが今回のシリーズのテーマです。
            色々な不満と申しましたが、一言で言うとまぁ維持が面倒で大変ということです。
            特に面倒だったのが画像の登録です。
            画像を1枚1枚トリミングして、縮小して、phpMyAdminで登録してゆくというのが何とも面倒で、いつの間にか更新も途絶えて、生きた屍のようなサイトになっていました。

            そこで今回のテーマは「誰でも簡単に登録できるようにしたい」です。
            具体的には、いわゆる登録フォームを作ってやって、そこから誰でもペパクラ情報を登録できるようにするのです。
            ここで細かい要件をリストアップしてみましょう。
             (1)登録フォームから新規登録ができること。
             (2)検索結果からの修正フォームが表示できること。
             (3)登録内容は登録者のみが自由に修正・削除できること(パスワード方式)
             (4)名前、地域、所属、パスワードは必ず入力させるようにすること。
             (5)アップロードされた画像は自動的に指定のサイズに縮小されること。
             (6)画像が指定されなかったら代わりに「NO IMAGE」画像が自動的に挿入されること。
             (7)画像はjpeg、png、gifを受け付けて、自動的にjpegに変換すること。
             (8)削除は、間違えて消さないように1クッション置くこと。
             (9)SQLインジェクション対策をとること(PDOの採用)。

            (1)登録フォームから新規登録ができること。
            どこかわかりやすいところにある「新規登録」ボタンを押すと、登録専用のブランクフォームが開きます。名前、所属、地域、url、コメントなどはテキスト入力、画像はファイルを指定してアップロード、分類や入手方法はラジオボタンで選択、パスワードは入力すると「●●●●●●●●」と表示されるのが素敵です。

            (2)検索結果からの修正フォームが表示できること。
            従来の検索結果画面の表に、「修正」の欄を設け、その欄にある「■」をクリックすると、登録済みの情報があらかじめ書き込まれた登録フォームが表示されます。ユーザーは必要な部分だけを直してパスワードを入力して「修正」を押すと、データが修正されます。

            (3)登録内容は登録者のみが自由に修正・削除できること(パスワード方式)
            情報の変更、削除には登録時に設定したパスワードが必要です。パスワードが無ければ勝手にデータベースをいじることはできません。(ただし管理人は自由に修正できるようになっています)

            (4)名前、地域、所属、パスワードは必ず入力させるようにすること。
            よくある登録フォームのように、入力漏れがあると、「×××を入力してください」と赤い字で表示されます。

            (5)アップロードされた画像は自動的に指定のサイズに縮小されること。
            ユーザは画像のサイズを気にせず、好きなサイズで画像をアップロードすると、スクリプトが自動的に画像サイズを規定の120×80px以内になるように縮小してくれます。

            (6)画像が指定されなかったら代わりに「NO IMAGE」画像が自動的に挿入されること。
            画像はまぁなくても情報量としては一応足りていると思いますので、画像のアップロードは任意とします。その代わりに、画像を指定せずに登録ボタンが押された場合は、代わりのブランク画像を自動で挿入してくれます。

            (7)画像はjpeg、png、gifを受け付けて、自動的にjpegに変換すること。
            これもユーザは画像のフォーマットを気にせず、自由にアップロードできるようになっています。

            (8)削除は、間違えて消さないように1クッション置くこと。
            削除ボタンを誤って押しただけで登録内容が消えてしまわないように、削除の場合は1クッション置き、別画面でパスワードを入力しないと消せないようになっています。

            (9)SQLインジェクション対策をとること(PDOの採用)。
            ユーザが登録できるようになるということは、特殊なクエリを挿入することでデータベースの中身を操作するSQLインジェクションを受けるリスクが高まることにもなります。これを避けるために、従来のMySql関数によるクエリ発行を止め、PDOという新しい方式でデータベースとやり取りするように変更します。


            2.全体構成
            従来のゆるキャラペパクラインデックスは次のような構成でした。
            ・本体(ypindex.php)
             └・画像表示スクリプト(ypimg.php)

            非常にシンプルです。これに対し今回作る改善後のファイル構成は次の通りです。
            ・本体(ypindex.php)
            ├・画像表示スクリプト(ypimg.php)
            └・新規登録・修正スクリプト(ypmod.php)
             ├・画像表示スクリプト(ypimg.php)
             └・削除スクリプト(ypdelete.php)

            画像表示スクリプトは前回の物をそのまま流用しますので、新たに作るのはypmod.phpとypdelete.phpの2本だけです。
            新規登録フォーム、修正フォーム、入力漏れ時の入力を促すフォーム、そしてデータの登録作業は全てypmod.phpで行い、削除に1クッションを要する削除スクリプトだけ別の構成となっています。


            それでは次回、順番が前後しますが(9)番のSQLインジェクション対策から具体的な中身に入っていこうと思います。
            次回以降の目次案は次の通りです。

            (2)SQLインジェクション対策
            ・PDOとは
            ・PDOによるデータベースアクセス方法
            ・ypindex.phpの改修
            (3)DB修正スクリプトの作成
            ・ypmod.phpの内部構成
            ・ypmod.phpの作成
            (4)画像登録処理
            ・画像の受け取り方
            ・画像の縮小方法
            ・画像の形式変換方法
            (5)削除スクリプトの作成
            ・ypdelete.phpの作成

            それではそれでは、次回をお楽しみに。


            スマートフォンサイトを作ろう!(8)viewport、そしてまた修正

            0
              JUGEMテーマ:wordpress

              終わったはずのシリーズに何故かまた投稿。

              それは、
              どうしても納得がいかなかったんです。
              なぜ、フォントサイズを48pxなんて大きな値にしないとちゃんと見えないのか。
              なぜ、シミュレータと実機であそこまで見栄えが違うのか。
              最初のあの文字の小ささ、あれじゃまるでPCサイトみたいじゃないか。





              そう思ったときに天啓が降りてきたのです。


              そうか、PCサイトだと思われていたのか!
              そういえば、私はスマホサイトですとブラウザに言った覚えは全然ないぞ。
              PCサイトは確か画面幅を980pxとして表示するとかどこかにかいてあったし。
              あの設定はどこでやるんだ!??

              そう思って調べたら出てきました。viewportです。

              viewportとは、スマホ特有の概念で、言ってみればブラウザの中にもう一つ仮想的なブラウザを作って表示している、という感じでしょうか。スマホのブラウザの中に980pxをぎゅっと縮めて押し込めているのです。これによりスマホでPCサイトの全貌を眺めることができるようになっているのです。このviewportの幅の設定がデフォルトのまま980pxになっていたのです。

              やるべきことは、次の1行をヘッダに入れてやることです。

              <meta name="viewport" content="width=device-width">

              これは、ブラウザの表示幅を実際のデバイスの幅に合わせなさい、という意味になります。
              早速やってみましょう。

              出た〜!出ました。全部の文字がでかでかになって出ました☆

              あぁ、ということはこれからまたレイアウト見ながら再調整か・・・まあ、仕方ない。

              まずはhtml,bodyのfont-sizeを16pxに戻します。これで文字サイズが1/3になって、980px→320〜360pxに対応してくれるはずです。
              出ました、出ました。うーん、もう少し字が大きくてもいいかな、とも思いますが、見出しのサイズなんかはまあいい感じなので、基準はこれで決めて、あとは要すればpタグにフォントサイズを与えていけばいいかな、と思います。

              で、あとは、いじってしまった画像サイズやメニューボタン、コメント枠などを順次修正していきます。
              といっても、ちまちまちまと直していくと、割と簡単に直りました。

              出来上がりはこちら
              ペーパークラフトが好きなんです
              ぜひ、スマートフォンでもご覧ください。


              ではでは、今度こそ本当にシリーズ終了です。
              ご清聴ありがとうございました。
              近いうちにまた次のシリーズでお会いしましょう。


              スマートフォンサイトを作ろう!(7)修正そして修正

              0
                JUGEMテーマ:wordpress

                スマホサイト初アップロードで出た不具合の数々をつぶしてゆきます。

                簡単なところから行くと、メニューの表示内容がおかしかった件、これはローカルの開発環境ではなくサーバの実環境のWordPressでメニューの設定をするのを忘れていたためでした。
                ローカルと同様にslider用のメニューを作ってやると、問題なく表示されました。

                問題はここから。
                ・タイトルの文字が小さい。
                ・でもサブタイトルの文字は普通に大きい。
                ・挨拶と更新情報の文字は、まあ大きい
                ・でもサムネール画像の下に書いた文字は全部ちっさい
                ・マージン関係もあらかた小さい
                ・グローバルメニューまで小さい。
                ・これら全部が、FireFox上のシミュレータとは体裁が全然違う。

                まずはとにかくシミュレータが役に立たないことは良くわかったので、実機のスマホを使った開発に切り替えます。
                具体的には、FFFTPを立ち上げっぱなしにしておいて、コードをいじったら即座にサーバに上げて、表示をスマホで見る、という段取りです。体裁の問題なのでいじるのはほぼstyle.cssだけでいいと思います。

                ではまずタイトル文字から。
                色々試行錯誤した結果から言いますと、えー、css内にあったコメントのせいで、h1タグに関する設定が読み込まれていなかったのが原因でした。PCに戻り、FireBugで実際に読み込まれているcssを確認したことで判明しました。やれやれ、要らないコメントは全部きれいに消して、さあこれでOK!
                と思ったら、あれ?反映されない?
                再度FireBugで確認したところ、今度は修正したcssが読み込まれていない。リロードが甘かったようです。
                「Control+F5」でスーパーリロードしたところ、無事に反映されました。
                でもいちいちControl+F5を押すのも面倒だな、第一スマホでスーパーリロードってやれんのか?と思っていたら、見つけました。WordPressのcssを呼び出す部分に細工をすることで、普通にリロードするだけで毎回自動的に最新のcssが読み込まれるようにすることができます。詳しくは
                kachibito.net
                さんに書いてありましたので、そちらもご覧ください。

                で、タイトル文字ですが、解決したかと思ったら大間違い。まだまだ深い謎があるようです。
                またまた試行錯誤の結果、変な現象にたどり着きました。
                h1タグのdisplayをblock, inline, inline-blockと変えると文字サイズが変わるのです。
                もう何だか意味不明です。
                ブラウザのデフォルトが意地悪しているかと思ってhtml5Doctorのリセットcssを使ってみましたが、変化はありません。
                仕方がないのでdisplayはinline-blockと決めて、文字サイズを調整しました。
                文字サイズの指定方法もpxをやめてremにしてみました。
                それと、スマホで長いタイトルを1行で表示するとどうしても文字が小さくなってしまうので、h1タグの中身をbloginfo('name');で出力するのをやめ、「ペーパークラフトが</br>好きなんです」と直接打ち込むことにしました。
                これでやっとこさ何とか調整が利くようになりました。

                次に、タイトル横のメニューボタン。
                これはcssで描いているわけですが、この線の幅やらマージンやらを全て4倍してやりました。これでOK。
                タイトルが2行になった分、マージンを調整してやって完了です。
                スライドメニューの中身はまた後ほど。

                次はトップ画像です。
                これは、width:100%を指定していた相手が画像そのものではなく、画像を含んだdiv要素だったのが原因のようです。div要素のid指定の横に「img」と足してやり、height:auto;としてやったところ、画面横幅ぴったりに表示されるようになりました。

                次に諸々の文字サイズ。
                もうこれはほんとに試行錯誤です。詳細は勘弁してください。
                ばくっと言うと、html,body要素のfont-sizeを48pxに上げてやり、あとはremで調整しました。

                次にメニューの幅。これはjPanelMenuの呼び出しオプションで、
                openPosition: '70%'
                としてやることで、絶対値ではなく画面幅基準で開いてくれるようになりました。
                併せて、メニューの上下のパディングも調節しました。

                それから、
                コメント欄の文字も大きくしました。
                キャプチャ画像も大きくしました。
                コメント欄の枠も大きくしました。
                管理人紹介のテーブルの幅も調節しました。
                管理人の似顔絵画像も大きくしました。

                そして最後に、ちっちゃくなっていたgoogleの広告も全部削除し、代わりにフッターにレスポンシブデザイン版のgoogleの広告を入れなおしました。


                終わりました。

                お疲れさまでした。

                あとは更新情報を書き込んで終了です。


                ということで、このシリーズはこれで終了です。
                皆様、次の企画をお楽しみに!
                 


                スマートフォンサイトを作ろう!(6)テンプレートをアップロードする

                0
                  JUGEMテーマ:wordpress

                  何故か終わったはずのシリーズがまた始まりましたが・・・?

                  とりあえず、前回までに作ったテンプレートをごっそりアップロードします。
                  PC用テンプレートフォルダの横にフォルダごとアップロードします。
                  そして「マルチデバイス」プラグインで、アップロードしたテンプレートを指定すると、作業完了!
                  早速、スマートフォンで実際の表示を見てみます。
                  すると・・・




                  な・・・なんだこの文字の大きさ、画像の大きさは!?
                  タイトルの文字ちっちゃい
                  メニューちっちゃい
                  メニューの中の文字もなんかずれてるし、
                  トップ画像がちっちゃいし、
                  項目名の文字も何だかイメージと違う、
                  見えてないけどブログ以下の記事の文字も、ちっさー!

                  ぜんっぜん指定したとおりになってないじゃんか!
                  いや、頭を冷やせ、そうじゃない、こういう指定になっていたということなのだ。

                  甘かった・・・実に甘かったよ・・・

                  簡単に行くと思ったのが大間違いだった・・・



                  ということで、終わるはずだったシリーズはまだまだ続くことになったのでした。


                  ちょっと色々調べて出直してきます!
                   


                  スマートフォンサイトを作ろう!(5)色々な体裁を整える

                  0
                    JUGEMテーマ:wordpress

                    さてそろそろこの短期集中連載も終わりが近づいてきました。
                    今回は、全体を眺めて、体裁のおかしいところを直していきます。

                    ということで、全体を眺めてみたところ、次の5つの問題が見つかりました。

                    (1) iPhone 3Gの画面サイズ(横幅320px)にすると、タイトルが長すぎて、メニューボタンが改行されてしまう。
                    (2) トップページでいきなりブログが始まる。前にサイドバーにあったご挨拶を復活させたい。
                    (3) iPhoneより幅が広い画面のスマホでは、サムネイル画像が左に寄ってしまう。
                    (4) 逆に320pxだと拡大画像が右にはみ出してしまう。
                    (5) コメント欄が右にはみ出している。

                    では一つ一つ対応細かく見ていきましょう。


                    (1) iPhone 3Gの画面サイズ(横幅320px)にすると、タイトルが長すぎて、メニューボタンが改行されてしまう。



                    ご覧のとおりです。これは高度なことを言わなければ簡単です。20ptの文字サイズを18ptに落としてみましょう。
                    するとこの通り、



                    まあ、いいんじゃないでしょうか。


                    (2) トップページでいきなりブログが始まる。前にサイドバーにあったご挨拶を復活させたい。

                    写真は(1)を見て頂くとして、トップ画像とブログコーナーの間に、ご挨拶と更新情報を入れてやりましょう。
                    以前サイドバーにあったコードをそのままコピペです。
                    するとこんな感じ。



                    なーんか、本文が真ん中に寄ってしまってますよね。マージン設定が大きすぎます。
                    このご挨拶と更新情報は.information-containerというクラスにしてありますので、これに対してマージンを新たに定義してやりましょう。調べると現状は左右それぞれ4emもありましたので、両方とも1emにしてやります。するとこんな感じ。



                    うーん、いいんじゃないでしょうか。


                    (3) iPhoneより幅が広い画面のスマホでは、サムネイル画像が左に寄ってしまう。



                    調べてみるとここは、画像のwidth:150px、margin-right:10pxという設定でした。320pxだとぴちぴちなので目立ちませんが、画面が大きくなるとずれが目立ちます。左にマージンが無いのも不自然ですよね。
                    ということで、width:45%、margin:0 5px 15pxにしました。するとこうなります。



                    まぁまぁまぁ、いいんじゃないでしょうか。


                    (4) 逆に320pxだと拡大画像が右にはみ出してしまう。



                    たしかにちょっと中心がずれているように見えます。
                    調べるとどうもこれはWordPressが吐き出すhtmlにwidth="325"と書かれているためのようです。
                    これはCSSで調整できますので、この画像のクラスを特定して100%指定にしてやりましょう。

                    #Contents #Main .image .wp-post-image{
                        width: 100%;
                        height: auto;
                    }

                    するとこうなります。



                    いい感じに真ん中にそろいました。


                    (5) コメント欄が右にはみ出している。



                    これはWordPressのcomment_form()のデフォルト設定のコメント欄幅が大きすぎるのが原因です。
                    こいつはオプションで修正してやりましょう。元々はデフォルトでの呼び出しだった、
                    <?php comment_form(); ?>

                    の部分を、次のように変えてやります。

                    <?php
                    $comment_field = '<p class="comment-form-comment"><label for="comment">' . _x( 'Comment', 'noun' ) . '</label><textarea id="comment" required="required" name="comment" cols="32" rows="8" aria-required="true"></textarea></p>';
                    $args = array('comment_field'=>$comment_field);
                    ?>
                    <?php comment_form($args); ?>

                    あと、マージンも広すぎるので、左右4em→2emくらいにしてやります。
                    すると、なんということでしょう、



                    ばっちりコメント欄が縮まりました。


                    ということで、あとはこれをサーバに公開して完了です!
                    最後までお付き合いありがとうございました。

                     


                    スマートフォンサイトを作ろう!(5)スライドメニューを整える

                    0
                      JUGEMテーマ:wordpress

                      さて今回の記事、最初にやりたいことがあります。
                      メニューボタンを、拾ってきた画像ではなく、よくある「3本線」にしたいんです。
                      何かうまい手はないか、と色々調べていたところ見つけたのがこちらの記事です。

                      【CSS】スマートフォンサイトでよく使われてる3本ラインのメニューアイコンをCSSだけで作ってみる

                      これこれ、これを探していたんです。もう完璧まるパクリで行かせていただきます。

                      まずhtmlはこの1行です。
                      <div id="global_nav"><a id="menu_button" class="ico-menu" href="#">menu</a></div>
                      


                      それから、CSSがこちら。
                      .ico-menu {
                          display: inline-block;
                          overflow: hidden;
                          position: relative;
                          width: 20px;
                          height: 0;
                          padding-top: 18px;
                          background: #000;
                      }
                      .ico-menu::before,
                      .ico-menu::after {
                          position: absolute;
                          left: 0;
                          content: "";
                          width: 20px;
                          height: 0;
                          border-top: 3px solid #fff;
                      }
                      .ico-menu::before {
                          top: 4px;
                      }
                      .ico-menu::after {
                          bottom: 4px;
                      }
                      #global_nav {
                          float: right;
                          margin:5px;
                      }
                      


                      併せてh1タグをfloatで左に寄せると、メニューボタンがタイトルの横に並んで、こうなります。


                      ほーら、いい感じ☆


                      続いて、開いたメニューの体裁を整えます。
                      こちらは、本家jPanelMenu.comの体裁をいただいちゃいます。
                      jPanelMenuのメニュー部分は、「jPanelMenu-menu」というidが自動的に付けられますので、このidに関するcssをコピってきました。
                      #jPanelMenu-menu{
                          background:#3b3b3b
                      }
                      

                      これはメニュー部分全体の背景色、濃いグレーです。
                       
                      #jPanelMenu-menu ul{
                          border-bottom:1px solid #484848
                      }
                      

                      これで、メニュー項目の間に薄い線を入れます。
                       
                      #jPanelMenu-menu li a{
                          background:#3b3b3b;
                          background:-o-linear-gradient(top, #3e3e3e, #383838);
                          background:-ms-linear-gradient(top, #3e3e3e, #383838);
                          background:-moz-linear-gradient(top, #3e3e3e, #383838);
                          background:-webkit-gradient(linear, left top, left bottom, color-stop(0, #3e3e3e), color-stop(1, #383838));
                          background:-webkit-linear-gradient(#3e3e3e, #383838);
                          background:linear-gradient(top, #3e3e3e, #383838);
                          font-family:"museo-sans","Museo Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
                          font-weight:300;
                          font-weight:700;
                          display:block;
                          padding:0.5em 5%;
                          border-top:1px solid #484848;
                          border-bottom:1px solid #2e2e2e;
                          text-decoration:none;
                          text-shadow:0 -1px 2px #222;
                          color:#f7f7f7
                      }
                      

                      これでメニュー項目の背景に軽いグラデーションを入れます。文字色はほぼ真っ白です。
                       
                      #jPanelMenu-menu li a:hover,#jPanelMenu-menu li a:focus{
                          background:#404040;
                          background:-o-linear-gradient(top, #484848, #383838);
                          background:-ms-linear-gradient(top, #484848, #383838);
                          background:-moz-linear-gradient(top, #484848, #383838);
                          background:-webkit-gradient(linear, left top, left bottom, color-stop(0, #484848), color-stop(1, #383838));
                          background:-webkit-linear-gradient(#484848, #383838);
                          background:linear-gradient(top, #484848, #383838)
                      }
                      

                      これで、マウスを乗せたりフォーカスが入った時のグラデーションの色を、やや明るくします。
                       
                      #jPanelMenu-menu li a:active{
                          background:#363636;
                          background:-o-linear-gradient(top, #3e3e3e, #2e2e2e);
                          background:-ms-linear-gradient(top, #3e3e3e, #2e2e2e);
                          background:-moz-linear-gradient(top, #3e3e3e, #2e2e2e);
                          background:-webkit-gradient(linear, left top, left bottom, color-stop(0, #3e3e3e), color-stop(1, #2e2e2e));
                          background:-webkit-linear-gradient(#3e3e3e, #2e2e2e);
                          background:linear-gradient(top, #3e3e3e, #2e2e2e);
                          -moz-box-shadow:0 2px 7px #222 inset;
                          -webkit-box-shadow:0 2px 7px #222 inset;
                          box-shadow:0 2px 7px #222 inset;
                          border-top-color:#222;
                          padding-top:0.55em;
                          padding-bottom:0.45em
                      }
                      

                      これでメニュー項目をタップしたときの背景を逆に少し濃くし、押された感を出しています。

                      ということで出来上がりはこちら。


                      さすが丸パクリだけあって、いい出来です。

                      次に、不要なメニューを消します。
                      トップにもともとあったグローバルメニューは、header.phpから削除します。
                      ただし、このグローバルメニューにclrfixがかけてありました(parallelというクラスを与えています)。この代わりにHeader部分にparallelクラスを与えてやります。
                      footer.phpに「もともと」あったメニューも、問答無用で削除します。

                      消し方が難しいのは、jPanelMenu用にfooterに入れたメニューです。これは、文字を画面外に飛ばし、floatで横に並べてしまいましょう。
                       
                      <div id="footer_menu">
                              <?php get_template_part('slider'); ?>
                      </div>
                      

                      というようにidを付けたら、
                       
                      #footer_menu {
                          text-indent: -9999px;
                          display:block;
                          float:left;
                      }
                      


                      これで、不要なメニューは全て消えました☆


                      それでは今回はここまで。次回はその他全体的な体裁を整えます。



                       



                      calendar

                      S M T W T F S
                           12
                      3456789
                      10111213141516
                      17181920212223
                      24252627282930
                      31      
                      << March 2024 >>

                      アクセスカウンタ

                      合計:
                      今日:
                      昨日:

                      selected entries

                      categories

                      archives

                      recent comment

                      • ホームページをリニューアルするの巻(19)−Googleウェブサイト翻訳ツールを組み込む
                        てちくん
                      • ホームページをリニューアルするの巻(19)−Googleウェブサイト翻訳ツールを組み込む
                        てちくん
                      • ホームページをリニューアルするの巻(19)−Googleウェブサイト翻訳ツールを組み込む
                        小田きく江
                      • ロリポブログでGoogleにサイトマップを登録する際の注意事項
                        てちくん
                      • ロリポブログでGoogleにサイトマップを登録する際の注意事項
                        suraugi
                      • いそべぇのペーパークラフトを作る(初級編)(12)
                        てちくん
                      • いそべぇのペーパークラフトを作る(初級編)(12)
                        だべえ
                      • noomでマイナス12kgのダイエットに成功!
                        Yoko

                      recommend

                      recommend

                      recommend

                      ドール デザートメーカー ヨナナス901
                      ドール デザートメーカー ヨナナス901 (JUGEMレビュー »)

                      結構高いんです、でも欲しいんです!

                      links

                      profile

                      書いた記事数:173
                      最近の更新日:2017/01/30

                      search this site.

                      others

                      mobile

                      qrcode

                      powered

                      無料ブログ作成サービス JUGEM

                      Google Adsense

                      楽天ブックス

                      楽天