====== PHP 1ファイルのみでDB不要のTODO管理ツール - Todo.php ====== コメントと更新履歴は[[http://0-oo.net/log/category/todo-php/|ゼロと無限の間のログ » Todo.php]]へどうぞ。 {{php-tool-box:pencil.png|}} ([[http://www.moongift.jp/|MOONGIFT]]風に)みなさんはタスク管理にどんなものを使っているだろうか。Webのサービスでもインストール型のツールでも、TODO管理の方法は色々あるが、いざ探してみると意外に帯に短し襷に長しである。\\ Remember The Milkは高機能だが重いし、Tracは共有するには良いが個人で使うには冗長、iGoogleのTODOガジェットはシンプルでよいが痒いところに手が届かない。\\ それならいっそ、自分のサーバで手軽に管理できるTODOツールはどうだろうか。今日紹介するのはPHPが1ファイルのみ、しかもDBも不要なTODO管理ツール、「Todo.php」だ。 ===== HTML5に対応 ===== バージョン0.2.xまではXHTML 1.0 Strictでしたが、バージョン0.3からはHTML5にしました。(主に属性等をシンプルにしただけですけど ;-) ) ===== 使い方 ===== 下記のソースコードをコピーして適当な名前でPHPファイルとして保存し、Todoクラスの先頭で定義してある定数(const)をお好みで変更してください。また、定数に合わせてデータを保存するディレクトリを作ってください。 なお、このソースコードではJavaScirptとCSSとして、操作性を高めるために[[../javascript/pryn-js-css|Pryn.js/css]]を、カレンダーを使うために[[../javascript/Yahho Calendar|Yahho Calendar]]と[[../javascript/Google Calendar Holidays|GCalendar Holidays]]を、フッターをページ最下部に表示するために[[../css-small-box/yahho-sticky-footer|Yahho Sticky Footer]]を使っていますが、これら無しでもTodo.phpは動きます。使わない場合はこれらのJavaScriptとCSSファイルを削除してください。 ===== サンプル ===== [[http://x.0-oo.net/sam/todo/?cat=Milk|Todo.phpのサンプル]] ===== さらに進んだ使い方 ===== メールサーバが使えるなら、[[mail to todo|mail2todo]]を組み合わせて使うと便利です。 ===== ライセンス ===== [[http://0-oo.net/pryn/MIT_license.txt|MITライセンス]]で。\\ ===== ソースコード ===== |]{1,20}$'; /** バックアップの保存期限 */ const BACKUP_TIME = '-7 day'; /** 優先度の最大値 */ const PRI_MAX = 5; public $cat; public $cats; public $list; /** * コンストラクタ * @param string $cat カテゴリ */ public function __construct($cat) { mb_internal_encoding(Todo::ENCODING); mb_regex_encoding(Todo::ENCODING); ini_set('default_charset', Todo::ENCODING); //HTTPヘッダーでの文字コード指定 ini_set('mbstring.strict_detection', true); mb_substitute_character(0x005f); //変換できない文字は"_"にする $this->cat = $this->_encode($cat); } /** * 表示の準備 */ public function setUp() { if ($this->isValidCat()) { if ($_REQUEST['delete'] && $this->_deleteCat()) { } else { if ($_POST['update']) { $this->_updateList(); } $this->list = $this->_getList(); } } $this->cats = $this->_getCategories(); } /** * カテゴリチェック * @return boolean 許可されるカテゴリかどうか */ public function isValidCat() { return mb_eregi(Todo::CAT_REGEX, $this->cat); } /** * TODOリストのファイルパスを取得する * @return string パス */ public function getPath() { $cat = mb_convert_encoding($this->cat, Todo::FILE_NAME_ENCODING); return Todo::DATA_DIR . '/' . $cat . '.txt'; } /** * 入力データの文字コードを正しく変換する * @param $input string 入力データ * @return string 文字コード変換後の入力データ */ private function _encode($input) { return mb_convert_encoding($input, Todo::ENCODING); } /** * カテゴリを全て取得する * @return array 全てのカテゴリのカテゴリ名とファイルサイズ */ private function _getCategories() { $h = openDir(Todo::DATA_DIR); if (!$h) { exit('data directory is not found.'); } $cats = array(); $limit = date('YmdHis', strToTime(Todo::BACKUP_TIME)); while (false !== ($file = readDir($h))) { if (is_dir($file)) { continue; } $arr = explode('.', $file); $path = Todo::DATA_DIR . '/' . $file; if (count($arr) == 3) { //バックアップの場合 if ($arr[2] < $limit) { //期限切れは削除 unlink($path); } } else { //最新版の場合 $cat = mb_convert_encoding($arr[0], Todo::ENCODING, Todo::FILE_NAME_ENCODING); $cats[$cat] = fileSize($path); } } closeDir($h); ksort($cats); return $cats; } /** * TODOリストを更新して保存する */ private function _updateList() { $oldCat = new Todo($_POST['oldcat']); //変更前のカテゴリ $newPath = $this->getPath(); if (is_file(strToUpper(__FILE__))) { //ファイルパスで大文字小文字を区別しない場合 $change = strCaseCmp($oldCat->cat, $this->cat); } else { $change = ($oldCat->cat != $this->cat); } if ($change && is_file($newPath)) { return; //変更後のカテゴリが既に存在する場合は更新しない } $oldPath = $oldCat->getPath(); if ($oldCat->isValidCat() && is_file($oldPath)) { rename($oldPath, $oldPath . '.' . date('YmdHis')); //バックアップ } foreach ($_POST['todo'] as $post) { if ($post[1] != '') { //TODO未入力は削除 $data .= implode("\t", array_map(array($this, '_encode'), $post)) . "\n"; } } file_put_contents($newPath, $data); } /** * TODOリストを取得する * @return array TODOリスト */ private function _getList() { $path = $this->getPath(); if (!is_file($path)) { //新規の場合 return array(''); } $list = explode("\n", file_get_contents($path)); rsort($list); //優先度順でソート return $list; } /** * カテゴリを削除する * @return boolean 削除できたかどうか */ private function _deleteCat() { $path = $this->getPath(); if (!is_file($path) || fileSize($path)) { //todoが残っている場合は削除させない return false; } $this->cat = null; return unlink($path); } } //----- HTMLレンダリング用のグローバル関数 ----- /** * HTMLエスケープ * @param string $val エスケープしたい文字列 * @return string エスケープした文字列 */ function h($val) { return htmlSpecialChars($val, ENT_QUOTES); } /** * option要素を出力する * @param string $val optionの値 * @param string $selected selectedにすべき値 */ function echoOption($val, $selectedVal) { if ($val == $selectedVal) { $selected = 'selected="selected"'; } echo "\n"; } //---------------------------------------------- $todo = new Todo($_REQUEST['cat']); $todo->setUp(); ?> TODO - <?php echo h($todo->cat) ?>

TODO

isValidCat()) { ?>
カテゴリ :
', '保留', '完了'); foreach ($todo->list as $i => $row) { $task = explode("\t", $row); if ($task[4] == $statuses[2]) { //完了は出力しない continue; } ?>
優先度TODO開始日期限状態
cat) { ?> 残念ですが、このカテゴリ名( cat) ?> )は使えません