px-files/_sys/php/site.php
private function load_sitemap_csv(){
		$path_sitemap_cache_dir = $this->px->get_realpath_homedir().'_sys/ram/caches/sitemaps/';

		// $path_top の設定値をチューニング
		$path_top = $this->conf->path_top;
		if(!strlen( $path_top )){ $path_top = '/'; }
		$path_top = preg_replace( '/\/$/s' , '/'.$this->px->get_directory_index_primary() , $path_top );//index.htmlを付加する。


		$i = 0;
		clearstatcache();
		while( @is_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' ) ){
			if( @filemtime( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' ) < time()-(60*60) ){
				// 60分以上更新された形跡がなければ、
				// ロックを解除して再生成を試みる。
				$this->px->fs()->rm( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' );
				break;
			}

			$i ++;
			if( $i > 0 ){
				// 他のプロセスがサイトマップキャッシュを作成中。
				// 2秒待って解除されなければ、true を返して終了する。 → 待たないように変更。
				$this->px->error('Sitemap cache generating is now in progress. This page has been incompletely generated.');

				//  古いサイトマップキャッシュが存在する場合、ロードする。
				$this->sitemap_array         = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap.array') ? @include($path_sitemap_cache_dir.'sitemap.array') : array() );
				$this->sitemap_id_map        = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_id_map.array') ? @include($path_sitemap_cache_dir.'sitemap_id_map.array') : array() );
				$this->sitemap_dynamic_paths = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_dynamic_paths.array') ? @include($path_sitemap_cache_dir.'sitemap_dynamic_paths.array') : array() );
				$this->sitemap_page_tree     = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_page_tree.array') ? @include($path_sitemap_cache_dir.'sitemap_page_tree.array') : array() );

				if( !count( $this->sitemap_array ) ){
					$this->sitemap_array = array(
						$path_top => array(
							'id' => '',
							'path' => $path_top,
							'content' => $path_top,
							'title' => 'HOME',
							'title_h1' => 'HOME',
							'title_label' => 'HOME',
							'title_breadcrumb' => 'HOME',
							'title_full' => 'HOME',
						)
					);
					$this->sitemap_id_map = array(
						''=>$path_top
					);
				}

				clearstatcache();
				if( !$this->px->fs()->is_file( $path_sitemap_cache_dir.'sitemap.sqlite' ) || !filesize($path_sitemap_cache_dir.'sitemap.sqlite') ){
					// サイトマップキャッシュ生成が不完全な状態でPDOでサイトマップの操作をしようとすると、
					// Fatal Error が発生する場合があるため、使えないようにしておく。
					//
					// sitemap.sqlite は、 $site の初期化時に同時に生成されるので、ファイルの存在確認だけでは不十分。
					// 準備が整う前の sitemap.sqlite は、容量が 0 のはずなので、これを条件に加えた。
					$this->pdo = false;
				}

				return false;
				break;
			}
			sleep(1);

			// PHPのFileStatusCacheをクリア
			clearstatcache();
		}

		if( $this->is_sitemap_cache() ){
			//  サイトマップキャッシュが存在する場合、キャッシュからロードする。
			$this->sitemap_array         = @include($path_sitemap_cache_dir.'sitemap.array');
			$this->sitemap_id_map        = @include($path_sitemap_cache_dir.'sitemap_id_map.array');
			$this->sitemap_dynamic_paths = @include($path_sitemap_cache_dir.'sitemap_dynamic_paths.array');
			$this->sitemap_page_tree     = @include($path_sitemap_cache_dir.'sitemap_page_tree.array');
			return true;
		}

		// サイトマップキャッシュ作成中のアプリケーションロックファイルを作成
		$lockfile_src = '';
		$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
		$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
		unset( $lockfile_src );

		// サイトマップキャッシュ生成中の一時データベースを作成
		if( class_exists('\\PDO') ){
			try {
				$tmp_pdo = new \PDO(
					'sqlite:'.$path_sitemap_cache_dir.'sitemap.sqlite.tmp',
					null, null,
					array(
						\PDO::ATTR_PERSISTENT => false, // ←これをtrueにすると、"持続的な接続" になる
					)
				);
			} catch (Exception $e) {
				$tmp_pdo = false;
			}
		}


		if( $tmp_pdo !== false ){
			// SQLiteキャッシュのテーブルを作成する
			ob_start();
?>
CREATE TABLE sitemap(
	id             TEXT UNIQUE,
	path           TEXT UNIQUE,
	parent_page_id TEXT,
	role         TEXT,
	orderby        INTEGER,
	list_flg       INTEGER
);
<?php
			$result = @$tmp_pdo->query(ob_get_clean());
			$result = @$tmp_pdo->query('DELETE FROM sitemap;');//既にDBが存在する場合を想定して、テーブルの内容を消去する
		}

		$path_sitemap_dir = $this->px->get_realpath_homedir().'sitemaps/';
		$ary_sitemap_files = $this->px->fs()->ls( $path_sitemap_dir );
		if( !is_array($ary_sitemap_files) ){
			$ary_sitemap_files = array();
		}
		sort($ary_sitemap_files);

		//  サイトマップをロード
		$num_auto_pid = 0;
		$tmp_sitemap_definition = array();
		$sitemap_page_originated_csv = array();
		// var_dump($ary_sitemap_files);
		foreach( $ary_sitemap_files as $basename_sitemap_csv ){
			if( strtolower( $this->px->fs()->get_extension($basename_sitemap_csv) ) != 'csv' ){
				// 拡張子がCSV意外のファイルは無視する
				continue;
			}
			if( strpos( $basename_sitemap_csv, '.~lock.' ) === 0 ){
				// Libre Office, Open Office 形式の一時ファイルを無視する
				continue;
			}
			// var_dump($basename_sitemap_csv);

			$tmp_sitemap = $this->px->fs()->read_csv( $path_sitemap_dir.$basename_sitemap_csv );
			foreach ($tmp_sitemap as $row_number=>$row) {
				// sleep(1); // 時間がかかる場合をシミュレーション

				set_time_limit(30);//タイマー延命
				$num_auto_pid++;
				$tmp_array = array();
				if( preg_match( '/^(?:\*)/is' , $row[0] ) ){
					if( $row_number > 0 ){
						// アスタリスク始まりの場合はコメント行とみなす。
						continue;
					}
					// アスタリスク始まりでも、0行目の場合は、定義行とみなす。
					// 定義行とみなす条件: 0行目で、かつA列の値がアスタリスク始まりであること。
					// ※アスタリスクで始まらない列は定義行として認めず、無視し、スキップする。
					$is_definition_row = false;
					foreach($row as $cell_value){
						if( preg_match( '/^(?:\*)/is' , $cell_value ) ){
							$is_definition_row = true;
							break;
						}
					}
					if( !$is_definition_row ){
						continue;
					}
					$tmp_sitemap_definition = array();
					$tmp_col_id = 'A';
					foreach($row as $tmp_col_number=>$cell_value){
						$col_name = trim( preg_replace('/^\*/si', '', $cell_value) );
						if( $col_name == $cell_value ){
							// アスタリスクで始まらない列は定義行として認めず、無視する。
							$tmp_col_id++;
							continue;
						}
						$tmp_sitemap_definition[$col_name] = array(
							'num'=>$tmp_col_number,
							'col'=>$tmp_col_id++,
							'key'=>$col_name,
							'name'=>$col_name,
						);
					}
					unset($is_definition_row);
					unset($cell_value);
					unset($col_name);
					continue;
				}
				foreach ($tmp_sitemap_definition as $defrow) {
					$tmp_array[$defrow['key']] = @$row[$defrow['num']];
				}

				// 前後の空白文字を削除する
				foreach(array('id', 'path', 'content', 'logical_path', 'list_flg', 'layout', 'orderby', 'category_top_flg', 'role', 'proc_type') as $tmpDefKey){
					if( @array_key_exists($tmpDefKey, $tmp_array) ){
						$tmp_array[$tmpDefKey] = @trim($tmp_array[$tmpDefKey]);
					}
				}

				if( !preg_match( '/^(?:\/|alias\:|data\:|javascript\:|\#|[a-zA-Z0-9]+\:\/\/)/is' , @$tmp_array['path'] ) ){
					// 不正な形式のチェック
					continue;
				}
				switch( $this->get_path_type( $tmp_array['path'] ) ){
					case 'full_url':
					case 'data':
					case 'javascript':
					case 'anchor':
						// 直リンク系のパスをエイリアス扱いにする
						$tmp_array['path'] = preg_replace('/^(?:alias:)?/s', 'alias:', $tmp_array['path']);
						break;
					default:
						// スラ止のパスに index.html を付加する。
						// ただし、JS、アンカー、外部リンクには適用しない。
						$tmp_array['path'] = preg_replace( '/\/((?:\?|\#).*)?$/s' , '/'.$this->px->get_directory_index_primary().'$1' , $tmp_array['path'] );
						break;
				}
				if( !array_key_exists('id', $tmp_array) || !strlen( @$tmp_array['id'] ) ){
					//ページID文字列を自動生成
					$tmp_id = ':auto_page_id.'.($num_auto_pid);
					$tmp_array['id'] = $tmp_id;
					unset($tmp_id);
				}

				// project.path_top の設定に対する処理
				if( $tmp_array['path'] == $path_top ){
					$tmp_array['id'] = '';
				}elseif( !strlen($tmp_array['id']) ){
					$tmp_array['id'] = ':auto_page_id.'.($num_auto_pid);
				}

				if($this->get_path_type( $tmp_array['path'] ) == 'dynamic'){
					// ダイナミックパスのインデックス作成
					$tmp_preg_pattern = $tmp_array['path'];
					$preg_pattern = '';
					while(1){
						if( !preg_match('/^(.*?)\{(\$|\*)([a-zA-Z0-9\-\_]*)\}(.*)$/s',$tmp_preg_pattern,$tmp_matched) ){
							$preg_pattern .= preg_quote($tmp_preg_pattern,'/');
							break;
						}
						$preg_pattern .= preg_quote($tmp_matched[1],'/');
						switch( $tmp_matched[2] ){
							case '$':
								$preg_pattern .= '([a-zA-Z0-9\-\_]+)';break;
							case '*':
								$preg_pattern .= '(.*?)';break;
						}
						$tmp_preg_pattern = $tmp_matched[4];
						continue;
					}
					preg_match_all('/\{(\$|\*)([a-zA-Z0-9\-\_]*)\}/',$tmp_array['path'],$pattern_map);
					$tmp_path_original = $tmp_array['path'];
					$tmp_array['path'] = preg_replace('/'.preg_quote('{','/').'(\$|\*)([a-zA-Z0-9\-\_]*)'.preg_quote('}','/').'/s','$2',$tmp_array['path']);
					array_push( $this->sitemap_dynamic_paths, array(
						'path'=>$tmp_array['path'],
						'path_original'=>$tmp_path_original,
						'id'=>$tmp_array['id'],
						'preg'=>'/^'.$preg_pattern.'$/s',
						'pattern_map'=>$pattern_map[2],
					) );
					if( !strlen( @$tmp_array['content'] ) ){
						$tmp_array['content'] = $tmp_array['path'];
					}
					$tmp_array['path'] = $tmp_path_original;
					unset($preg_pattern);
					unset($pattern_map);
					unset($tmp_path_original);
				}

				if( !array_key_exists('content', $tmp_array) || !strlen( @$tmp_array['content'] ) ){
					$tmp_array['content'] = $tmp_array['path'];
					$tmp_array['content'] = preg_replace('/(?:\?|\#).*$/s','',$tmp_array['content']);
					// $tmp_array['content'] = preg_replace('/\/$/s','/'.$this->px->get_directory_index_primary(), $tmp_array['content']);
				}
				$tmp_array['content'] = preg_replace( '/\/$/s','/'.$this->px->get_directory_index_primary(), $tmp_array['content'] );//index.htmlを付加する。
				if( preg_match( '/^alias\:/s' , $tmp_array['path'] ) ){
					//エイリアスの値調整
					$tmp_array['content'] = null;
					$tmp_array['path'] = preg_replace( '/^alias\:/s' , 'alias'.$num_auto_pid.':' , $tmp_array['path'] );
				}

				//  パンくず欄の先頭が > から始まっていた場合、削除
				$tmp_array['logical_path'] = @preg_replace( '/^\>+/s' , '' , $tmp_array['logical_path'] );

				$this->sitemap_array[$tmp_array['path']] = $tmp_array;
				$this->sitemap_id_map[$tmp_array['id']] = $tmp_array['path'];

				$sitemap_page_originated_csv[$tmp_array['path']] = array(
					'basename'=>$basename_sitemap_csv,
					'row'=>$row_number,
				);

				// サイトマップキャッシュ作成中のアプリケーションロックファイルを更新
				$lockfile_src = '';
				$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
				$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
				$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
				unset( $lockfile_src );
			}
		}
		//  / サイトマップをロード

		// ダイナミックパスを並び替え
		usort($this->sitemap_dynamic_paths, function($a,$b){
			$path_short_a = preg_replace( '/\{.*$/si', '', $a['path_original'] );
			$path_short_b = preg_replace( '/\{.*$/si', '', $b['path_original'] );
			if( strlen($path_short_a) > strlen($path_short_b) ){ return -1; }
			if( strlen($path_short_a) < strlen($path_short_b) ){ return  1; }
			if( $path_short_a > $path_short_b ){ return -1; }
			if( $path_short_a < $path_short_b ){ return  1; }
			return 0;
		});

		//  ページツリー情報を構成
		if( $tmp_pdo !== false ){
			// INSERT文をストア
			ob_start(); ?>
INSERT INTO sitemap(
	id,
	path,
	parent_page_id,
	role,
	orderby,
	list_flg
)VALUES(
	:id,
	:path,
	:parent_page_id,
	:role,
	:orderby,
	:list_flg
);
<?php
			$sth = $tmp_pdo->prepare( ob_get_clean() );
		}
		$this->sitemap_page_tree = array();
		foreach( $this->sitemap_array as $tmp_path=>$tmp_page_info ){
			set_time_limit(30);//タイマー延命
			// sleep(1); // 時間がかかる場合をシミュレーション
			if( $tmp_pdo !== false ){
				$parent_page_id = explode('>', $tmp_page_info['logical_path']);
				$parent_page_id = $parent_page_id[count($parent_page_id)-1];
				if(is_null(@$this->sitemap_id_map[$parent_page_id])){
					$parent_page_id = preg_replace( '/\/((?:\?|\#).*)?$/s' , '/'.$this->px->get_directory_index_primary().'$1' , $parent_page_id );
					$parent_page_id = @$this->sitemap_array[$parent_page_id]['id'];
				}

				// var_dump($role_id);
				$sth->execute(array(
					':id'=>@$tmp_page_info['id'],
					':path'=>@$tmp_page_info['path'],
					':parent_page_id'=>$parent_page_id,
					':role'=>@$this->get_role($tmp_page_info['id']),
					':orderby'=>@$tmp_page_info['orderby'],
					':list_flg'=>@$tmp_page_info['list_flg'],
				));
			}else{
				$this->get_children( $tmp_path );
			}

			// サイトマップキャッシュ作成中のアプリケーションロックファイルを更新
			$lockfile_src = '';
			$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
			$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
			$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
			unset( $lockfile_src );
		}
		set_time_limit(30);//タイマーリセット
		unset($tmp_path, $tmp_page_info );

		//  キャッシュディレクトリを作成
		set_time_limit(0);//タイマー延命
		$this->px->fs()->mkdir($path_sitemap_cache_dir);

		// キャッシュファイルを作成
		if( $tmp_pdo !== false ){

			// disconnect
			$sth = null;
			unset($sth);
			$tmp_pdo = null;
			unset($tmp_pdo);
			$this->pdo = null;

			$i = 0;
			while( !$this->px->fs()->copy(
				$path_sitemap_cache_dir.'sitemap.sqlite.tmp',
				$path_sitemap_cache_dir.'sitemap.sqlite'
			) ){
				$i ++;
				if( $i > 10 ){
					// 10秒待って完了できなければ終了
					break;
				}
				sleep(1);
			}

			// PDO をリロード
			$this->pdo = new \PDO(
				'sqlite:'.$path_sitemap_cache_dir.'sitemap.sqlite',
				null, null,
				array(
					\PDO::ATTR_PERSISTENT => false, // ←これをtrueにすると、"持続的な接続" になる
				)
			);

			// remove tmp database
			@$this->px->fs()->rm( $path_sitemap_cache_dir.'sitemap.sqlite.tmp' );
		}
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap.array' , self::data2phpsrc($this->sitemap_array) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_id_map.array' , self::data2phpsrc($this->sitemap_id_map) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_dynamic_paths.array' , self::data2phpsrc($this->sitemap_dynamic_paths) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_page_tree.array' , self::data2phpsrc($this->sitemap_page_tree) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_page_originated_csv.array' , self::data2phpsrc($sitemap_page_originated_csv) );

		// サイトマップキャッシュ作成中のアプリケーションロックを解除
		$this->px->fs()->rm( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' );

		set_time_limit(30);//タイマーリセット

		return true;
	}
private function load_sitemap_csv(){
		$path_sitemap_cache_dir = $this->px->get_realpath_homedir().'_sys/ram/caches/sitemaps/';

		// $path_top の設定値をチューニング
		$path_top = $this->conf->path_top;
		if(!strlen( $path_top )){ $path_top = '/'; }
		$path_top = preg_replace( '/\/$/s' , '/'.$this->px->get_directory_index_primary() , $path_top );//index.htmlを付加する。


		$i = 0;
		clearstatcache();
		while( @is_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' ) ){
			if( @filemtime( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' ) < time()-(60*60) ){
				// 60分以上更新された形跡がなければ、
				// ロックを解除して再生成を試みる。
				$this->px->fs()->rm( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' );
				break;
			}

			$i ++;
			if( $i > 0 ){
				// 他のプロセスがサイトマップキャッシュを作成中。
				// 2秒待って解除されなければ、true を返して終了する。 → 待たないように変更。
				$this->px->error('Sitemap cache generating is now in progress. This page has been incompletely generated.');

				//  古いサイトマップキャッシュが存在する場合、ロードする。
				$this->sitemap_array         = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap.array') ? @include($path_sitemap_cache_dir.'sitemap.array') : array() );
				$this->sitemap_id_map        = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_id_map.array') ? @include($path_sitemap_cache_dir.'sitemap_id_map.array') : array() );
				$this->sitemap_dynamic_paths = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_dynamic_paths.array') ? @include($path_sitemap_cache_dir.'sitemap_dynamic_paths.array') : array() );
				$this->sitemap_page_tree     = ( $this->px->fs()->is_file($path_sitemap_cache_dir.'sitemap_page_tree.array') ? @include($path_sitemap_cache_dir.'sitemap_page_tree.array') : array() );

				if( !count( $this->sitemap_array ) ){
					$this->sitemap_array = array(
						$path_top => array(
							'id' => '',
							'path' => $path_top,
							'content' => $path_top,
							'title' => 'HOME',
							'title_h1' => 'HOME',
							'title_label' => 'HOME',
							'title_breadcrumb' => 'HOME',
							'title_full' => 'HOME',
						)
					);
					$this->sitemap_id_map = array(
						''=>$path_top
					);
				}

				clearstatcache();
				if( !$this->px->fs()->is_file( $path_sitemap_cache_dir.'sitemap.sqlite' ) || !filesize($path_sitemap_cache_dir.'sitemap.sqlite') ){
					// サイトマップキャッシュ生成が不完全な状態でPDOでサイトマップの操作をしようとすると、
					// Fatal Error が発生する場合があるため、使えないようにしておく。
					//
					// sitemap.sqlite は、 $site の初期化時に同時に生成されるので、ファイルの存在確認だけでは不十分。
					// 準備が整う前の sitemap.sqlite は、容量が 0 のはずなので、これを条件に加えた。
					$this->pdo = false;
				}

				return false;
				break;
			}
			sleep(1);

			// PHPのFileStatusCacheをクリア
			clearstatcache();
		}

		if( $this->is_sitemap_cache() ){
			//  サイトマップキャッシュが存在する場合、キャッシュからロードする。
			$this->sitemap_array         = @include($path_sitemap_cache_dir.'sitemap.array');
			$this->sitemap_id_map        = @include($path_sitemap_cache_dir.'sitemap_id_map.array');
			$this->sitemap_dynamic_paths = @include($path_sitemap_cache_dir.'sitemap_dynamic_paths.array');
			$this->sitemap_page_tree     = @include($path_sitemap_cache_dir.'sitemap_page_tree.array');
			return true;
		}

		// サイトマップキャッシュ作成中のアプリケーションロックファイルを作成
		$lockfile_src = '';
		$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
		$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
		unset( $lockfile_src );

		// サイトマップキャッシュ生成中の一時データベースを作成
		if( class_exists('\\PDO') ){
			try {
				$tmp_pdo = new \PDO(
					'sqlite:'.$path_sitemap_cache_dir.'sitemap.sqlite.tmp',
					null, null,
					array(
						\PDO::ATTR_PERSISTENT => false, // ←これをtrueにすると、"持続的な接続" になる
					)
				);
			} catch (Exception $e) {
				$tmp_pdo = false;
			}
		}


		if( $tmp_pdo !== false ){
			// SQLiteキャッシュのテーブルを作成する
			ob_start();
?>
CREATE TABLE sitemap(
	id             TEXT UNIQUE,
	path           TEXT UNIQUE,
	parent_page_id TEXT,
	role         TEXT,
	orderby        INTEGER,
	list_flg       INTEGER
);
<?php
			$result = @$tmp_pdo->query(ob_get_clean());
			$result = @$tmp_pdo->query('DELETE FROM sitemap;');//既にDBが存在する場合を想定して、テーブルの内容を消去する
		}

		$path_sitemap_dir = $this->px->get_realpath_homedir().'sitemaps/';
		$ary_sitemap_files = $this->px->fs()->ls( $path_sitemap_dir );
		if( !is_array($ary_sitemap_files) ){
			$ary_sitemap_files = array();
		}
		sort($ary_sitemap_files);

		//  サイトマップをロード
		$num_auto_pid = 0;
		$tmp_sitemap_definition = array();
		$sitemap_page_originated_csv = array();
		// var_dump($ary_sitemap_files);
		foreach( $ary_sitemap_files as $basename_sitemap_csv ){
			if( strtolower( $this->px->fs()->get_extension($basename_sitemap_csv) ) != 'csv' ){
				// 拡張子がCSV意外のファイルは無視する
				continue;
			}
			if( strpos( $basename_sitemap_csv, '.~lock.' ) === 0 ){
				// Libre Office, Open Office 形式の一時ファイルを無視する
				continue;
			}
			// var_dump($basename_sitemap_csv);

			$tmp_sitemap = $this->px->fs()->read_csv( $path_sitemap_dir.$basename_sitemap_csv );
			foreach ($tmp_sitemap as $row_number=>$row) {
				// sleep(1); // 時間がかかる場合をシミュレーション

				set_time_limit(30);//タイマー延命
				$num_auto_pid++;
				$tmp_array = array();
				if( preg_match( '/^(?:\*)/is' , $row[0] ) ){
					if( $row_number > 0 ){
						// アスタリスク始まりの場合はコメント行とみなす。
						continue;
					}
					// アスタリスク始まりでも、0行目の場合は、定義行とみなす。
					// 定義行とみなす条件: 0行目で、かつA列の値がアスタリスク始まりであること。
					// ※アスタリスクで始まらない列は定義行として認めず、無視し、スキップする。
					$is_definition_row = false;
					foreach($row as $cell_value){
						if( preg_match( '/^(?:\*)/is' , $cell_value ) ){
							$is_definition_row = true;
							break;
						}
					}
					if( !$is_definition_row ){
						continue;
					}
					$tmp_sitemap_definition = array();
					$tmp_col_id = 'A';
					foreach($row as $tmp_col_number=>$cell_value){
						$col_name = trim( preg_replace('/^\*/si', '', $cell_value) );
						if( $col_name == $cell_value ){
							// アスタリスクで始まらない列は定義行として認めず、無視する。
							$tmp_col_id++;
							continue;
						}
						$tmp_sitemap_definition[$col_name] = array(
							'num'=>$tmp_col_number,
							'col'=>$tmp_col_id++,
							'key'=>$col_name,
							'name'=>$col_name,
						);
					}
					unset($is_definition_row);
					unset($cell_value);
					unset($col_name);
					continue;
				}
				foreach ($tmp_sitemap_definition as $defrow) {
					$tmp_array[$defrow['key']] = @$row[$defrow['num']];
				}

				// 前後の空白文字を削除する
				foreach(array('id', 'path', 'content', 'logical_path', 'list_flg', 'layout', 'orderby', 'category_top_flg', 'role', 'proc_type') as $tmpDefKey){
					if( @array_key_exists($tmpDefKey, $tmp_array) ){
						$tmp_array[$tmpDefKey] = @trim($tmp_array[$tmpDefKey]);
					}
				}

				if( !preg_match( '/^(?:\/|alias\:|data\:|javascript\:|\#|[a-zA-Z0-9]+\:\/\/)/is' , @$tmp_array['path'] ) ){
					// 不正な形式のチェック
					continue;
				}
				switch( $this->get_path_type( $tmp_array['path'] ) ){
					case 'full_url':
					case 'data':
					case 'javascript':
					case 'anchor':
						// 直リンク系のパスをエイリアス扱いにする
						$tmp_array['path'] = preg_replace('/^(?:alias:)?/s', 'alias:', $tmp_array['path']);
						break;
					default:
						// スラ止のパスに index.html を付加する。
						// ただし、JS、アンカー、外部リンクには適用しない。
						$tmp_array['path'] = preg_replace( '/\/((?:\?|\#).*)?$/s' , '/'.$this->px->get_directory_index_primary().'$1' , $tmp_array['path'] );
						break;
				}
				if( !array_key_exists('id', $tmp_array) || !strlen( @$tmp_array['id'] ) ){
					//ページID文字列を自動生成
					$tmp_id = ':auto_page_id.'.($num_auto_pid);
					$tmp_array['id'] = $tmp_id;
					unset($tmp_id);
				}

				// project.path_top の設定に対する処理
				if( $tmp_array['path'] == $path_top ){
					$tmp_array['id'] = '';
				}elseif( !strlen($tmp_array['id']) ){
					$tmp_array['id'] = ':auto_page_id.'.($num_auto_pid);
				}

				if($this->get_path_type( $tmp_array['path'] ) == 'dynamic'){
					// ダイナミックパスのインデックス作成
					$tmp_preg_pattern = $tmp_array['path'];
					$preg_pattern = '';
					while(1){
						if( !preg_match('/^(.*?)\{(\$|\*)([a-zA-Z0-9\-\_]*)\}(.*)$/s',$tmp_preg_pattern,$tmp_matched) ){
							$preg_pattern .= preg_quote($tmp_preg_pattern,'/');
							break;
						}
						$preg_pattern .= preg_quote($tmp_matched[1],'/');
						switch( $tmp_matched[2] ){
							case '$':
								$preg_pattern .= '([a-zA-Z0-9\-\_]+)';break;
							case '*':
								$preg_pattern .= '(.*?)';break;
						}
						$tmp_preg_pattern = $tmp_matched[4];
						continue;
					}
					preg_match_all('/\{(\$|\*)([a-zA-Z0-9\-\_]*)\}/',$tmp_array['path'],$pattern_map);
					$tmp_path_original = $tmp_array['path'];
					$tmp_array['path'] = preg_replace('/'.preg_quote('{','/').'(\$|\*)([a-zA-Z0-9\-\_]*)'.preg_quote('}','/').'/s','$2',$tmp_array['path']);
					array_push( $this->sitemap_dynamic_paths, array(
						'path'=>$tmp_array['path'],
						'path_original'=>$tmp_path_original,
						'id'=>$tmp_array['id'],
						'preg'=>'/^'.$preg_pattern.'$/s',
						'pattern_map'=>$pattern_map[2],
					) );
					if( !strlen( @$tmp_array['content'] ) ){
						$tmp_array['content'] = $tmp_array['path'];
					}
					$tmp_array['path'] = $tmp_path_original;
					unset($preg_pattern);
					unset($pattern_map);
					unset($tmp_path_original);
				}

				if( !array_key_exists('content', $tmp_array) || !strlen( @$tmp_array['content'] ) ){
					$tmp_array['content'] = $tmp_array['path'];
					$tmp_array['content'] = preg_replace('/(?:\?|\#).*$/s','',$tmp_array['content']);
					// $tmp_array['content'] = preg_replace('/\/$/s','/'.$this->px->get_directory_index_primary(), $tmp_array['content']);
				}
				$tmp_array['content'] = preg_replace( '/\/$/s','/'.$this->px->get_directory_index_primary(), $tmp_array['content'] );//index.htmlを付加する。
				if( preg_match( '/^alias\:/s' , $tmp_array['path'] ) ){
					//エイリアスの値調整
					$tmp_array['content'] = null;
					$tmp_array['path'] = preg_replace( '/^alias\:/s' , 'alias'.$num_auto_pid.':' , $tmp_array['path'] );
				}

				//  パンくず欄の先頭が > から始まっていた場合、削除
				$tmp_array['logical_path'] = @preg_replace( '/^\>+/s' , '' , $tmp_array['logical_path'] );

				$this->sitemap_array[$tmp_array['path']] = $tmp_array;
				$this->sitemap_id_map[$tmp_array['id']] = $tmp_array['path'];

				$sitemap_page_originated_csv[$tmp_array['path']] = array(
					'basename'=>$basename_sitemap_csv,
					'row'=>$row_number,
				);

				// サイトマップキャッシュ作成中のアプリケーションロックファイルを更新
				$lockfile_src = '';
				$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
				$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
				$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
				unset( $lockfile_src );
			}
		}
		//  / サイトマップをロード

		// ダイナミックパスを並び替え
		usort($this->sitemap_dynamic_paths, function($a,$b){
			$path_short_a = preg_replace( '/\{.*$/si', '', $a['path_original'] );
			$path_short_b = preg_replace( '/\{.*$/si', '', $b['path_original'] );
			if( strlen($path_short_a) > strlen($path_short_b) ){ return -1; }
			if( strlen($path_short_a) < strlen($path_short_b) ){ return  1; }
			if( $path_short_a > $path_short_b ){ return -1; }
			if( $path_short_a < $path_short_b ){ return  1; }
			return 0;
		});

		//  ページツリー情報を構成
		if( $tmp_pdo !== false ){
			// INSERT文をストア
			ob_start(); ?>
INSERT INTO sitemap(
	id,
	path,
	parent_page_id,
	role,
	orderby,
	list_flg
)VALUES(
	:id,
	:path,
	:parent_page_id,
	:role,
	:orderby,
	:list_flg
);
<?php
			$sth = $tmp_pdo->prepare( ob_get_clean() );
		}
		$this->sitemap_page_tree = array();
		foreach( $this->sitemap_array as $tmp_path=>$tmp_page_info ){
			set_time_limit(30);//タイマー延命
			// sleep(1); // 時間がかかる場合をシミュレーション
			if( $tmp_pdo !== false ){
				$parent_page_id = explode('>', $tmp_page_info['logical_path']);
				$parent_page_id = $parent_page_id[count($parent_page_id)-1];
				if(is_null(@$this->sitemap_id_map[$parent_page_id])){
					$parent_page_id = preg_replace( '/\/((?:\?|\#).*)?$/s' , '/'.$this->px->get_directory_index_primary().'$1' , $parent_page_id );
					$parent_page_id = @$this->sitemap_array[$parent_page_id]['id'];
				}

				// var_dump($role_id);
				$sth->execute(array(
					':id'=>@$tmp_page_info['id'],
					':path'=>@$tmp_page_info['path'],
					':parent_page_id'=>$parent_page_id,
					':role'=>@$this->get_role($tmp_page_info['id']),
					':orderby'=>@$tmp_page_info['orderby'],
					':list_flg'=>@$tmp_page_info['list_flg'],
				));
			}else{
				$this->get_children( $tmp_path );
			}

			// サイトマップキャッシュ作成中のアプリケーションロックファイルを更新
			$lockfile_src = '';
			$lockfile_src .= 'ProcessID='.getmypid()."\r\n";
			$lockfile_src .= @date( 'Y-m-d H:i:s' , time() )."\r\n";
			$this->px->fs()->save_file( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' , $lockfile_src );
			unset( $lockfile_src );
		}
		set_time_limit(30);//タイマーリセット
		unset($tmp_path, $tmp_page_info );

		//  キャッシュディレクトリを作成
		set_time_limit(0);//タイマー延命
		$this->px->fs()->mkdir($path_sitemap_cache_dir);

		// キャッシュファイルを作成
		if( $tmp_pdo !== false ){

			// disconnect
			$sth = null;
			unset($sth);
			$tmp_pdo = null;
			unset($tmp_pdo);
			$this->pdo = null;

			$i = 0;
			while( !$this->px->fs()->copy(
				$path_sitemap_cache_dir.'sitemap.sqlite.tmp',
				$path_sitemap_cache_dir.'sitemap.sqlite'
			) ){
				$i ++;
				if( $i > 10 ){
					// 10秒待って完了できなければ終了
					break;
				}
				sleep(1);
			}

			// PDO をリロード
			$this->pdo = new \PDO(
				'sqlite:'.$path_sitemap_cache_dir.'sitemap.sqlite',
				null, null,
				array(
					\PDO::ATTR_PERSISTENT => false, // ←これをtrueにすると、"持続的な接続" になる
				)
			);

			// remove tmp database
			@$this->px->fs()->rm( $path_sitemap_cache_dir.'sitemap.sqlite.tmp' );
		}
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap.array' , self::data2phpsrc($this->sitemap_array) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_id_map.array' , self::data2phpsrc($this->sitemap_id_map) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_dynamic_paths.array' , self::data2phpsrc($this->sitemap_dynamic_paths) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_page_tree.array' , self::data2phpsrc($this->sitemap_page_tree) );
		$this->px->fs()->save_file( $path_sitemap_cache_dir.'sitemap_page_originated_csv.array' , self::data2phpsrc($sitemap_page_originated_csv) );

		// サイトマップキャッシュ作成中のアプリケーションロックを解除
		$this->px->fs()->rm( $path_sitemap_cache_dir.'making_sitemap_cache.lock.txt' );

		set_time_limit(30);//タイマーリセット

		return true;
	}
サイトマップCSVを読み込む。

サイトマップディレクトリに格納されたサイトマップCSV (`./px-files/sitemaps/*.csv`) を読み込み、パースします。

この処理は、サイトマップの行数や階層構造によっては、重い処理になります。
そのため、このメソッドは、パースした後の配列情報をキャッシュディレクトリ(`./px-files/_sys/ram/caches/sitemaps/`)にキャッシュし、
次回以降はキャッシュを読み込むことで重い処理を回避します。

このキャッシュは、キャッシュファイルのタイムスタンプより新しいCSVを発見するか、
`?PX=clearcache` によりキャッシュがクリアされると、次回アクセス時に再生成されます。

@return bool 成功時に `true`, 失敗時に `false` を返します。