# [メタ情報]
# 識別子: 公開用スクリプトのリスト表示_exe
# システム名: 公開用スクリプトのリスト表示、functions.phpに置く
# 技術種別: Misc
# 機能名: Misc
# 使用言語: php
# 状態: 実行用
# [/メタ情報]
/* =========================================================
* 3) 公開用TXTリスト: [pub_txt_list]
* - iOS文字化け対策として、表示は ?pubtxt=... 経由に変更
* - DL は ?pubtxt=...&dl=1 で添付配信
* =======================================================*/
add_shortcode('pub_txt_list', function($atts){
$dir_path = WP_CONTENT_DIR . '/pmedia/scripts_pub';
$base_url = content_url('pmedia/scripts_pub');
$allowed_exts = ['txt'];
$exclude_files = ['key_patterns.txt'];
$limit = isset($atts['limit']) ? max(1, intval($atts['limit'])) : 0;
$uid = 'pub-txt-' . (function_exists('wp_generate_uuid4') ? wp_generate_uuid4() : uniqid());
if (!is_dir($dir_path) || !is_readable($dir_path)) {
return '
一覧ディレクトリにアクセスできませんでした:'.esc_html($dir_path).'
';
}
// ▼ 日付フォーマッタ:wp_date → date_i18n → gmdate の順で確実に文字列を返す
$fmt = function($format, $ts){
if (function_exists('wp_date')) {
$s = wp_date($format, $ts);
if ($s !== false && $s !== '') return $s;
}
if (function_exists('date_i18n')) {
$s = date_i18n($format, $ts, false);
if ($s !== false && $s !== '') return $s;
}
return gmdate($format, $ts);
};
// 収集
$items = [];
$latest_mtime = 0; // 一覧の最終更新(最大mtime)
if ($dh = opendir($dir_path)) {
while (($entry = readdir($dh)) !== false) {
if ($entry === '.' || $entry === '..') continue;
if (in_array($entry, $exclude_files, true)) continue;
$full = $dir_path . '/' . $entry;
if (!is_file($full) || !is_readable($full)) continue;
clearstatcache(true, $full); // ← statキャッシュを都度クリア
$ext = strtolower(pathinfo($entry, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_exts, true)) continue;
$mtime = @filemtime($full);
if ($mtime === false) {
$ctime = @filectime($full);
$mtime = ($ctime !== false) ? $ctime : 0; // フォールバック
}
$size = @filesize($full); if ($size === false) $size = 0;
if ($mtime > $latest_mtime) $latest_mtime = $mtime;
$items[] = [
'name' => $entry,
'url' => trailingslashit($base_url) . rawurlencode($entry), // 直リンク(DLボタンのfallback用に残す)
'mtime' => $mtime,
'size' => $size,
];
}
closedir($dh);
}
if (empty($items)) return '対象ファイル(.txt)は見つかりませんでした。
';
// サーバー側初期ソート(JS無効時のため)
$validSort = ['name','mtime','size'];
$sort = (isset($_GET['sort']) && in_array($_GET['sort'], $validSort, true)) ? $_GET['sort'] : 'mtime';
$order = (isset($_GET['order']) && strtolower($_GET['order']) === 'asc') ? 'asc' : 'desc';
usort($items, function($a, $b) use ($sort, $order){
$va = $a[$sort]; $vb = $b[$sort];
$cmp = ($sort === 'name') ? strcmp(mb_strtolower($va), mb_strtolower($vb)) : ($va <=> $vb);
return ($order === 'asc') ? $cmp : -$cmp;
});
if ($limit > 0 && count($items) > $limit) {
$items = array_slice($items, 0, $limit);
// limit を掛けた後の「表示中」だけで右肩日付を出す場合は再計算も可
}
// 行
$rows = '';
foreach ($items as $it) {
$date_d = esc_html( $fmt('Y-m-d', $it['mtime']) );
$date_t = esc_html( $fmt('H:i:s', $it['mtime']) );
$fname = esc_html($it['name']);
// サイズ 2段表示(数値 + 単位)
$size_str = size_format($it['size'], 2);
if (preg_match('/^([\d\.]+)\s*(\w+)$/', $size_str, $m)) {
$size_html = ''.$m[1].'
'.$m[2].'';
} else {
$size_html = esc_html($size_str);
}
// PCではスペース、スマホでは改行
$date_html = ''.$date_d.''
. '
'
. ' '
. ''.$date_t.'';
// ▼ iOS文字化け回避:表示は ?pubtxt=..., DLは ?pubtxt=...&dl=1
$view_url = add_query_arg('pubtxt', $it['name'], home_url('/'));
$dl_url = add_query_arg(['pubtxt' => $it['name'], 'dl' => '1'], home_url('/'));
$rows .= ''
. ''.$fname.' | '
. ''.$date_html.' | '
. ''.$size_html.' | '
. ''
. 'DL'
. ' | '
. '
';
}
// 初期矢印
$arrowTxt = function($key) use ($sort, $order) {
if ($key !== $sort) return '';
return $order === 'asc' ? ' ▲' : ' ▼';
};
// 右肩:一覧の最終更新日(全体の最新 mtime)
$list_updated_text = esc_html( $fmt('Y.m.d', $latest_mtime) );
ob_start(); ?>
※ ヘッダーをクリックして並び替え(再読み込み不要)