274 lines
7.2 KiB
PHP
Executable File
274 lines
7.2 KiB
PHP
Executable File
<?php
|
|
|
|
class PgnParser
|
|
{
|
|
|
|
private $pgnFile;
|
|
private $pgnContent;
|
|
private $pgnGames;
|
|
private $gameParser;
|
|
private $pgnGameParser;
|
|
private $_fullParsing = true;
|
|
|
|
public function __construct($pgnFile = "", $fullParsing = true)
|
|
{
|
|
if ($pgnFile) {
|
|
$this->pgnFile = $this->sanitize($pgnFile);
|
|
|
|
if (!file_exists($this->pgnFile)) {
|
|
throw new Exception("File not found: " . $this->pgnFile);
|
|
}
|
|
}
|
|
|
|
$this->_fullParsing = $fullParsing;
|
|
$this->gameParser = new GameParser();
|
|
$this->pgnGameParser = new PgnGameParser();
|
|
}
|
|
|
|
private function sanitize($filePath)
|
|
{
|
|
$extension = $this->getExtension($filePath);
|
|
if ($extension != 'pgn') return null;
|
|
|
|
if (class_exists("LudoDBRegistry")) {
|
|
$tempPath = LudoDBRegistry::get('FILE_UPLOAD_PATH');
|
|
} else {
|
|
$tempPath = null;
|
|
}
|
|
|
|
if (isset($tempPath) && substr($filePath, 0, strlen($tempPath)) == $tempPath) {
|
|
|
|
} else {
|
|
if (substr($filePath, 0, 1) === "/") return null;
|
|
}
|
|
$filePath = preg_replace("/[^0-9\.a-z_\-\/]/si", "", $filePath);
|
|
|
|
if (!file_exists($filePath)) return null;
|
|
|
|
return $filePath;
|
|
|
|
}
|
|
|
|
private function getExtension($filePath)
|
|
{
|
|
$tokens = explode(".", $filePath);
|
|
return strtolower(array_pop($tokens));
|
|
}
|
|
|
|
|
|
public function setPgnContent($content)
|
|
{
|
|
$this->pgnContent = $content;
|
|
}
|
|
|
|
private function cleanPgn()
|
|
{
|
|
$c = $this->pgnContent;
|
|
|
|
/* replace CR and TAB with space */
|
|
$c = preg_replace("/[\t\r]/s", " ", $c);
|
|
|
|
/* separate first comment of variation */
|
|
$c = str_replace("({", "( {", $c);
|
|
|
|
/* replace 0 in castle with O */
|
|
$c = str_replace("0-0-0", "O-O-O", $c);
|
|
$c = str_replace("0-0", "O-O", $c);
|
|
|
|
/* basic trimming:
|
|
* - remove initial blanks
|
|
* - keep only one space
|
|
* - trim lines
|
|
* - max 2 consecutive '\n'
|
|
*/
|
|
$c = preg_replace("/^\s+([^\s])/", "$1", $c);
|
|
$c = preg_replace("/ +/", " ", $c);
|
|
$c = preg_replace("/\s*\n\s*/", "\n", $c);
|
|
$c = preg_replace("/\n{3,}/s", "\n\n", $c);
|
|
|
|
/* replace '[' between '{' and '}' with '//--SB--//'
|
|
*/
|
|
$c = preg_replace('/(?:\G(?!\A)|\{)[^\}\[]*\K\[/', "//--SB--//", $c);
|
|
$c = preg_replace('/(?:\G(?!\A)|\{)[^\}\]]*\K\]/', "//--SE--//", $c);
|
|
|
|
/* set one '\n' between tags.
|
|
* This is possible because brackets within comments are protected above
|
|
*/
|
|
$c = preg_replace('/"\]\s*\[/s', "\"]\n[", $c);
|
|
|
|
/* set '\n\n' between tags and movetext section
|
|
* set '\n\n' between non tag line and tag line (between two games)
|
|
* This is possible because brackets within comments are protected above
|
|
*/
|
|
$c = preg_replace('/"\]\s*([\.0-9]|{)/s', "\"]\n\n$1", $c);
|
|
$c = preg_replace("/([^\]])\n+\[/", "$1\n\n[", $c);
|
|
|
|
/* revert brackets within movetext comments */
|
|
$c = str_replace("//--SB--//", "[", $c);
|
|
$c = str_replace("//--SE--//", "]", $c);
|
|
|
|
return $c;
|
|
}
|
|
|
|
public static function getArrayOfGames($pgn)
|
|
{
|
|
return self::getPgnGamesAsArray($pgn);
|
|
}
|
|
|
|
private function splitPgnIntoGames($pgnString)
|
|
{
|
|
return $this->getPgnGamesAsArray($pgnString);
|
|
}
|
|
|
|
private function getPgnGamesAsArray($pgn)
|
|
{
|
|
$ret = array();
|
|
$content = "\n\n" . $pgn;
|
|
$games = preg_split("/\n\n\[/s", $content, -1, PREG_SPLIT_DELIM_CAPTURE);
|
|
|
|
//file_put_contents("/tmp/parsed.pgn", $content);
|
|
|
|
for ($i = 1, $count = count($games); $i < $count; $i++) {
|
|
$gameContent = trim("[" . $games[$i]);
|
|
if (strlen($gameContent) > 10) {
|
|
array_push($ret, $gameContent);
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
public function getGamesAsJSON()
|
|
{
|
|
return json_encode($this->getGames());
|
|
}
|
|
|
|
private function fullParsing()
|
|
{
|
|
return $this->_fullParsing;
|
|
}
|
|
|
|
public function getUnparsedGames()
|
|
{
|
|
if (!isset($this->pgnGames)) {
|
|
if ($this->pgnFile && !isset($this->pgnContent)) {
|
|
|
|
$this->pgnContent = file_get_contents($this->pgnFile);
|
|
}
|
|
$this->pgnGames = $this->splitPgnIntoGames($this->cleanPgn($this->pgnContent));
|
|
}
|
|
|
|
return $this->pgnGames;
|
|
}
|
|
|
|
public function countGames()
|
|
{
|
|
$games = $this->getUnparsedGames();
|
|
return count($games);
|
|
}
|
|
|
|
public function getCleanPgn()
|
|
{
|
|
return $this->cleanPgn($this->pgnContent);
|
|
}
|
|
|
|
public function getFirstGame()
|
|
{
|
|
return $this->getGameByIndex(0);
|
|
}
|
|
|
|
public function getGameByIndexShort($index)
|
|
{
|
|
$games = $this->getUnparsedGames();
|
|
if (count($games) && count($games) > $index) {
|
|
$game = $this->getParsedGame($games[$index]);
|
|
$game["moves"] = $this->toShortVersion($game["moves"]);
|
|
return $game;
|
|
}
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
public function getGameByIndex($index)
|
|
{
|
|
$games = $this->getUnparsedGames();
|
|
if (count($games) && count($games) > $index) {
|
|
return $this->getParsedGame($games[$index]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function getGames()
|
|
{
|
|
return $this->getParsedGames(false);
|
|
}
|
|
|
|
public function getGamesShort()
|
|
{
|
|
return $this->getParsedGames(true);
|
|
}
|
|
|
|
private function getParsedGames($short = false)
|
|
{
|
|
$games = $this->getUnparsedGames();
|
|
$ret = array();
|
|
for ($i = 0, $count = count($games); $i < $count; $i++) {
|
|
try {
|
|
$g = $short ? $this->getParsedGameShort($games[$i]) : $this->getParsedGame($games[$i]);
|
|
$ret[] = $g;
|
|
|
|
} catch (Exception $e) {
|
|
|
|
}
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
|
|
private function toShortVersion($branch)
|
|
{
|
|
foreach ($branch as &$move) {
|
|
|
|
if (isset($move["from"])) {
|
|
$move["n"] = $move["from"] . $move["to"];
|
|
unset($move["fen"]);
|
|
unset($move["from"]);
|
|
unset($move["to"]);
|
|
if (isset($move["variations"])) {
|
|
$move["v"] = array();
|
|
foreach ($move["variations"] as $variation) {
|
|
$move["v"][] = $this->toShortVersion($variation);
|
|
}
|
|
}
|
|
unset($move["variations"]);
|
|
}
|
|
|
|
}
|
|
return $branch;
|
|
}
|
|
|
|
|
|
private function getParsedGame($unParsedGame)
|
|
{
|
|
$this->pgnGameParser->setPgn($unParsedGame);
|
|
$ret = $this->pgnGameParser->getParsedData();
|
|
if ($this->fullParsing()) {
|
|
$ret = $this->gameParser->getParsedGame($ret);
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
private function getParsedGameShort($unParsedGame)
|
|
{
|
|
$this->pgnGameParser->setPgn($unParsedGame);
|
|
$ret = $this->pgnGameParser->getParsedData();
|
|
if ($this->fullParsing()) {
|
|
$ret = $this->gameParser->getParsedGame($ret, true);
|
|
$moves = &$ret["moves"];
|
|
$moves = $this->toShortVersion($moves);
|
|
}
|
|
return $ret;
|
|
}
|
|
}
|