PukiWikiプラグイン開発から学ぶPHP #4

# 前回
https://qiita.com/PitaQ/items/d627c6888eca95ab6f4e

# 本題
今回はテーブルに行を追加するプラグインをつくります。
まあcommentやvoteみたいにそのページの内容自体を変更しようということです。

ファイル名は `addrow.inc.php` です。

## 設計
`#addrow`

- #addrow をテーブル書式で書かれた行の下に追加すると次の行を追加するための入力フォームを設置
- フォームには、テーブルの列に応じて入力欄を置く
- 送信すると入力されたデータがそのテーブルに行として追加され、ページを更新する

# 開発
### ソース
```addrow.inc.php
<?php
function plugin_addrow_init() {
  // グローバル変数の作成 $_addrow_messages
  $messages['_addrow_messages'] = [
    'en' => [
      'insert' => 'Insert',
    ],
    'ja' => [
      'insert' => '挿入',
    ],
  ];

  set_plugin_messages($messages);
}

function plugin_addrow_convert() {
  global $vars, $_addrow_messages;

  // 関数内での静的変数
  static $count = 0;  
  
  $count++;

  $page = $vars['page'];

  $lines = get_source($page); // ページの各行１つ１つを配列して取得

  $count2 = 0;
  
  $size = count($lines); // 行数 (配列の要素数)
  for ($i = 0; $i < $size; $i++) {
    $line = $lines[$i];

    // 正規表現で処理中の行が #addrow(...) であるかをチェック
    if (!preg_match('/^#addrow\(?.*?\)?$/', $line, $matches))
      continue;

    $count2++;

    if ($count2 != $count) 
      continue;
      
    $tableline = $lines[$i - 1];
    $divcount = substr_count($tableline, '|'); // 特定の文字をカウント
    
    if ($divcount < 2)
      return "#addrow: Invalid table";

    // LANG定数はpukiwiki.ini.phpで定義する言語を指定するためのもの ja, enなど
    $addbtn = $_addrow_messages[LANG]['insert'];
    
    $html = '<form method="post">' . "\n";
    $html .= '<input type="hidden" name="cmd" value="addrow" />' . "\n";
    $html .= '<input type="hidden" name="page" value="' . htmlsc($page) . '" />' . "\n";

    //                                                      md5ハッシュ値を取得
    $html .= '<input type="hidden" name="digest" value="' . md5($tableline) . '" />' . "\n";
    $html .= '<input type="hidden" name="count" value="' . $count . '" />' . "\n";

    for ($j = 0; $j < $divcount - 1; $j++) {
      $html .= '<input type="text" name="addrow[' . $j . ']" value="" size="8" />' . "\n";
    }

    $html .= '<input type="submit" value="' . $addbtn . '" />' . "\n";

    $html .= '</form>';
    
    return $html;
  }
  
  return "#addrow: Not found";
}

function plugin_addrow_action() {
  global $vars;

  if (!isset($vars['count'])) {
    return ['msg' => 'missing parameters', 'body' => ''];
  }
  
  $count = $vars['count'];
  $page = $vars['page'];
  $digest = $vars['digest'];

  $postdata = '';
  
  $lines = get_source($page); // ページの各行１つ１つを配列して取得

  $count2 = 1;

  $size = count($lines);
  for ($i = 0; $i < $size $i++) {
    $line = $lines[$i];
    
    if (!preg_match('/^#addrow\(?.*?\)?$/', $line, $matches)) {
      $postdata .= $line;
      continue;
    }

    $tableline = $lines[$i - 1];
    $divcount = substr_count($tableline, '|'); // 特定の文字をカウント
    
    if ($divcount < 2)
      return ['msg' => 'addrow.inc.php', 'body' => '#addrow: Invalid table'];

    $addbtn = $_addrow_messages[LANG]['insert'];
    
    if ($count != $count2) {
      $postdata .= $line;
      continue;
    }
    $count2++;

    // 他の編集者との重複対策にハッシュ値が同じかチェック
    if ($digest != md5($tableline)) 
      return ['msg' => 'invalid digest', 'body' => ''];

    $addrow = [];

    $postdata .= '|';
    for ($j = 0; $j < $divcount - 1; $j++) {
      $addrow[$j] = $vars['addrow'][$j];
      $postdata .= $addrow[$j] . '|';
    }

    $postdata .= "\n";
    
    // 挿入した行よりあとの文章($i から count($lines) までの内容)と連結する。
    for ($j = $i; $j < count($lines); $j++) {
      $postdata .= $lines[$j];
    }

    // ページを上書き
    page_write($page, $postdata);

    return ['msg' => 'Inserted table row', ''];
  }

  return ['msg' => 'Not found', 'body' => ''];
}
```

## 関数内の静的変数について
```php
function hoge() {
    // 初回のみ初期化される
    static $count = 0;

    $count++;
}
```
関数内の静的変数はクラスの静的変数とは関係なく、ローカル変数が一時的でなく初回だけ初期化されそれ以降は値を維持できます。

用途としては関数が呼ばれた回数を保存するなどに。