2012-06-02

Java 腦袋學 PHP Web Form Page

form.php


<?php include 'inc/base.php' ?>

<?php
// PHP 自動提供 $_GET、$_POST、$_ENV、$_COOKIE、$_SERVER、$_FILES 等多個 global 陣列
// 不要用 register_globals 將上述陣列的 key/value 轉為 global 變數,很危險的
// 盡量用明確的 $_GET 或 $_POST,不要偷懶用 $_REQUEST
// $_REQUEST 依照 variables_order 定義的順序,依序將 $_GET、$_POST、$_ENV、$_COOKIE、$_SERVER 多個陣列整合成單一陣列


// 用一個 php 負責 get 與 post,以減少程式不一致的機會
// $_SERVER['REQUEST_METHOD'] 取得大寫的 GET 或者 POST

// POST - 送出 form
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

  $b = backingObject();

  // binding & validate
  $errors = array();

  $b->account = Moca::validateString('account', $errors, true, 50);
  $b->password = Moca::validateString('password', $errors, true, 50);
  $b->status = Moca::validateRadio('status', $errors, User::$STATUS);
  $b->type = Moca::validateString('type', $errors, false, 50);
  $b->description = Moca::validateString('description', $errors, false, 200);
  $b->power = Moca::validateCheckbox('power', $errors, User::$POWER);
  $b->score = Moca::validatePint('score', $errors, true);

  if (!count($errors)) {
    if (isset($b->id)) {
      $msg = User::update($b);
    }
    else {
      $msg = User::add($b);
    }
    if (isset($msg)) {
      $errors['account'] = $msg;
    }
    else {
      header('Location: userList.php');
      exit();
    }
  }
}
// GET - 進 form
else if ($_SERVER['REQUEST_METHOD'] == 'GET') {
  $b = backingObject();
}
else {
  echo "不支援的 REQUEST_METHOD - {$_SERVER['REQUEST_METHOD']}";
  exit();
}

function backingObject() {
  $id = Moca::findId();
  // 有傳 id 表示要修改
  if (isset($id)) {
    // load from database
    $b = User::get($id);
  }
  // 沒有傳 id 表示要新增
  else {
    $b = new User();
    $b->createTime = time();
  }
  return $b;
}
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<?php include 'inc/head.php' ?>
<script type="text/javascript">
</script>
</head>

<body>
<table cellspacing="0" cellpadding="3" width="100%">
    <tbody>
        <tr>
            <td>使用者管理</td>
        </tr>
        <tr>
            <td height="5"></td>
        </tr>
    </tbody>
</table>
<table width="720" align="center">
    <tbody>
        <tr>
            <td>
            <table width="100%">
                <tbody>
                    <tr>
                        <td>
            <!--  因為用同一個 php 處理 get 與 post,所以可以用 $_SERVER['SCRIPT_NAME'] 以減少更名造成的錯誤 -->
                        <form id="userForm" action="<?php echo $_SERVER['SCRIPT_NAME'] ?>"
                            method="post"><input type="hidden" class="text" id="id" name="id"
                            value="<?php echo $b->id; ?>" />
                        <table width="100%" border="1" cellspacing="1" cellpadding="2">
                            <tr>
                                <td align="left" class="required">帳號</td>
                                <td><input name="account" type="text" id="account"
                                    value="<?php echo $b->account ?>" class="text" /><?php Moca::showError('account'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="required">密碼</td>
                                <td><input name="password" id="password" type="password"
                                    class="text" value="<?php echo $b->password ?>" /><?php Moca::showError('password'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="required">狀態</td>
                                <td><?php foreach (User::$STATUS as $key => $value) { ?> <input
                                    name="status" type="radio" value="<?php echo $key; ?>"
                                    class="radio"
                                    <?php echo $b->status == $key ? 'checked="checked"' : ''; ?> /><?php echo $value; ?>
                                    <?php } ?><?php Moca::showError('status'); ?></td>
                            </tr>
                            <tr>
                                <td align="left">類型</td>
                                <td><input name="type" id="type" type="text" class="text"
                                    value="<?php echo $b->type ?>" /><?php Moca::showError('type'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="required">Email</td>
                                <td><input name="email" id="email" type="text" class="text"
                                    value="<?php echo $b->email ?>" /><?php Moca::showError('email'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="m_tdcolor_04">備註說明</td>
                                <td><textarea name="description" id="description"
                                    class="textarea"><?php echo $b->description ?></textarea><?php Moca::showError('description'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="m_tdcolor_04">權限</td>
                                <td><?php
                                foreach (User::$POWER as $key => $value ) {
                                  $checked = strpos($b->power, $key) !== false ? "checked='checked'" : "";
                                  // name 要加上 [],告知 PHP 以陣列處理
                                  echo "<input type='checkbox' name='power[]' value='$key' $checked/>$value<br/>";
                                }
                                ?><?php Moca::showError('power'); ?></td>
                            </tr>
                            <tr>
                                <td align="left" class="required">分數</td>
                                <td><input name="scroe" id="scroe" type="text" class="text"
                                    value="<?php echo $b->scroe ?>" /><?php Moca::showError('scroe'); ?></td>
                            </tr>
                            <tr>
                                <td colspan="2" align="center"><input type="submit"
                                    class="button" value="存檔" />    <input type="button"
                                    class="button" value="取消" onclick="history.back(); " />
                                   <input type="reset" class="button" value="重設" />
                                 </td>
                            </tr>
                        </table>
                        </form>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</body>
</html>

base.php


<?php

date_default_timezone_set('Asia/Taipei');
setlocale(LC_ALL, 'zh_TW');
session_start();

class Moca {

  // 日期時間 long 變 字串
  public static function formatDT($t) {
    if (!isset($t)) {
      return;
    }
    if (strlen($t) === 0) {
      return;
    }
    return date('Y-m-d H:i', $t);
  }

  // 日期 long 變 字串
  public static function formatD($t) {
    if (!isset($t)) {
      return;
    }
    if (strlen($t) === 0) {
      return;
    }
    return date('Y-m-d', $t);
  }

  // 日期字串變 long
  public static function parseDT($t) {
    if (!isset($t)) {
      return;
    }
    if (strlen($t) === 0) {
      return;
    }
    return strtotime($t);
  }

  // 從陣列中取出對應的錯誤訊息
  public static function showError($field) {
    global $errors;
    if (isset($errors) && isset($errors[$field])) {
      print " <span class='error'>$errors[$field]</span>";
    }
  }

  // PHP 的 strlen() 不支援 Unicode,網路抄來的解法
  public static function strlen($s) {
    $a = preg_split("//u", $s);
    $i = -2;
    foreach ($a as $b)
    $i++;
    return $i;
  }
 
  public static function findId() {
    $id = NULL;
    // GET - 進 form
    if (isset($_GET['id']) && ctype_digit($_GET['id'])) {
      $id = trim($_GET['id']);
    }
    // POST - 送出 form
    else if (isset($_POST['id']) && ctype_digit($_POST['id'])) {
      $id = trim($_POST['id']);
    }
    return $id;
  }

  // 字串用 strlen() 驗證長度,text、textarea 與 file 都會送出字串
  // PHP 的 strlen() 不支援 Unicode
  // 不可用 empty() 取代 strlen(),因為 empty() 會將某些字串視為 false,如字元 0
  // 檢查長度前,最好先用 trim() 整理一下
  public static function validateString($field, &$errors, $required, $max) {
    // 未傳入或者傳入空字串
    // 注意:http://...?account=&password=123,$_POST['account'] 為空字串,$_POST['name'] 才是未傳入
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else if (Moca::strlen(trim($_POST[$field])) > $max) {
      $errors[$field] = "長度必須不可超過 $max 個字元";
    }
    return isset($_POST[$field]) ? trim($_POST[$field]) : '';
  }

  // 驗證正整數用 ctype_digit()
  // is_numeric 不適合做數值驗證,因為它接受一堆奇怪的格式
  public static function validatePint($field, &$errors, $required) {
    $value = NULL;
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else if (!ctype_digit(trim($_POST[$field]))) {
      $errors[$field] = "必須為正整數";
    }
    else {
      $value = intval(trim($_POST[$field]));
    }
    return $value;
  }

  // 驗證整數,先用 intval 將字串轉為整數,再用 strval 將整數轉回字串,最後和原字串比較
  public static function validateInt($field, &$errors, $required) {
    $value = NULL;
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else if ( trim($_POST[$field]) != strval(intval(trim($_POST[$field])))) {
      $errors[$field] = "必須為整數";
    }
    else {
      $value = intval(trim($_POST[$field]));
    }
    return $value;
  }

  // 驗證浮點數,先用 floatval 將字串轉為浮點數,再用 strval 將浮點數轉回字串,最後和原字串比較
  public static function validateInt($field, &$errors, $required) {
    $value = NULL;
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else if ( trim($_POST[$field]) != strval(floatval(trim($_POST[$field])))) {
      $errors[$field] = "必須為浮點數";
    }
    else {
      $value = floatval(trim($_POST[$field]));
    }
    return $value;
  }

  // 輸入 2012-06-01,輸出日期 long
  public static function validateDate($field, &$errors, $required) {
    $value = NULL;
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else {
      $value = Moca::parseDT(trim($_POST[$field]));;
    }
    return $value;
  }

  // 輸入 2012-06-01、時與分,輸出日期 long
  public static function validateDateTime($field, &$errors, $required) {
    $value = NULL;
    if (!isset($_POST[$field]) || Moca::strlen(trim($_POST[$field])) === 0) {
      if ($required) {
        $errors[$field] = '必填欄位';
      }
    }
    else {
      $h = str_pad($_POST[$field.'_h'], 2, '0', STR_PAD_LEFT);
      $m = str_pad($_POST[$field.'_m'], 2, '0', STR_PAD_LEFT);
      $dt = trim($_POST[$field]).' '.$h.':'.$m;
      $value = Moca::parseDT($dt);
    }
    return $value;
  }

  // 用 array_key_exists 做 double check
  public static function validateRadio($field, &$errors, $array) {
    if (!isset($_POST[$field])) {
      $errors[$field] = '必填欄位';
    }
    else if (!array_key_exists($_POST[$field], $array)) {
      $errors[$field] = "所勾選的值不存在";
    }
    return isset($_POST[$field]) ? trim($_POST[$field]) : '';
  }

  // 使用 array_intersect 取得交集以確認勾選的項目均存在
  public static function validateCheckbox($field, &$errors, $array) {
    if (isset($_POST[$field])) {
      if (array_intersect($_POST[$field], array_keys($array)) != $_POST[$field]) {
        $errors[$field] = '所勾選的值不存在';
      }
      else {
        return $_POST[$field];
      }
    }
    return NULL;
  }
}
?>

沒有留言:

張貼留言