Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
Dort wird nach dem ECO-Feld weiter Input Felder erzeugt, obwohl schon Züge in den Zeilen stehen.
Weiter wird das Result und Date nur verkürzt ausgegeben. "Result 1-" statt "Result 1-0", Datum Verkürzt auf 9 Zeichen.
Ich habe eine leise Ahnung warum das so ist, je nach dem woher die Datei stammt, könnte \r\n als newline oder nur \n dort in den Zeilen stehen. Dann müsste man das zurechtgestutze der Werte um 1 verringern.
Ahso, die Frage war auf den pgn-parser bezogen, wie hast Du die Beispieldatei geschrieben? In der Readme ist ja gar nichts zu lesen, wie man ihn benutzt. Kann er auch die Header Felder auslesen?
Und die zusätzlichen/falschen Inputs? Woher kommen die? Die Textarea bleibt leer bei der .pgn von den Neckar Open.
Hm stimmt schon. Für die Schachseite habe ich 2 Wochen den Quellcode von dem pgn-viewer gelesen und modifiziert. Der zeigt die .pgn als Schachbrett an. Die unteren Knöpfe habe ich dazu geschrieben und noch einige andere Sachen, Koordinaten z.b. Das erste mal öffnen des Quellcode war lustig. Habe geschaut wie viele Zeilen er hat, ca. 4200. Da dachte ich mir "wtf? Das ist die Suche nach der Nadel im Heuhaufen". Naja nach einiger Zeit habe ich die "Nadeln" dann gefunden und umgeschrieben. Habe 2 Wochen gebraucht um alles so zu ändern, dass es mir gefällt. Habe sogar den Author angeschrieben, der mir noch einige wichtige Tips gegeben hat. Aber jetzt noch den pgn-parser von amyboyd analysieren? Naja, nicht so viel lust zu. Er/sie hätte ja mal einfach ein paar Zeilen mehr in die Readme schreiben können und mir viel Mühe ersparen können
Naja, so kompliziert ist es echt nicht. Der nächste Schritt wäre, direkt beim Upload die Daten der .pgn aufzudröseln und in die MySQL Datenbank zu schreiben. Dann hab ich das gefummel mit den Dateien nicht mehr. Dazu könnte man "SELECT * FROM Table WHERE White = :name OR Black = :name" ausführen und hätte alle Partien des Spielers, dazu eine Eröffnungsdatenbank etc. Wenn ich das noch für Zugumstellungen, die zur gleichen Position führen, schaffe, wäre das der Overkill
Hi, ich bin's mal wieder
Ich habe jetzt versucht das MovesArray mit serialize() in die Datenbank zu schreiben. Klappt auch ganz gut, das schreiben zumindest. Jetzt habe ich mit phpMyAdmin mir das angeschaut und festgestellt, dass dort folgendes steht:
das ist sehr cryptisch, aber mir fällt das a:120 auf. In jeder Zeile steht a: und einige Zahlen. Dazu habe ich folgendes MySQL Query:
Code:
$select = "SELECT * FROM " . $p->filetable . " WHERE MovesClean = :mc";
$stmt = $p->con->prepare($select);
$stmt->bindParam(":mc", $serialmoves);
$stmt->execute();
if ($stmt->rowCount() > 0) {
echo "already in database<br>\n";
} else {
Dieses Query soll verhindern, dass doppelte Paritien noch einmal geschrieben werden, bzw. dass jede Partie nur einmal in der DB steht.
Weiß jemand wofür das a:123 steht? Es funktioniert mir ein bisschen zu perfekt, ich habe aus einer .pgn mit 140+ Partien eine Partie ausgesucht und in eine andere Datei geschrieben und trotzdem wurde sie als dublikat aussortiert. Das funktioniert mir echt ein wenig zu perfekt.
Edit: Ach, eigenen Kopf vielleicht mal benutzen: a = Array, die Zahl ist die Anzahl der Elemente... höchstwarscheinlich...
Für die Googler oder sonstige, die es intressiert: In der .pgn stehen manchmal in "Zug-Zeilen" ein [ als erstes Zeichen, z.b. [%clk 1:38]....
Das kann man mit der Zeile
Code:
if ((strpos($line, '[') === 0) && (ctype_alpha(substr($line,1,1)) === true)) {...
beheben. Es wird dann nicht nur geprüft, ob die Zeile mit [ beginnt, sondern auch ob das Zeichen danach ein Buchstabe ist, also nicht % oder sonstiges. Ist natürlich immer noch nicht perfekt, denn in den Kommentaren könnte sicher auch "[Matt in 4 Zügen]" oder ähnliches stehen, aber fürs erste reicht der Hotfix.
Servus, mal wieder was neues, die Schachdatenbank hat die nächste Versionsstufe erreicht. Es sind Momentan über 5000 Partien gelistet, komplett perfekt läuft es noch nicht, aber vorzeigbar.
Hi, es sind mal wieder einige Wochen ins Land gezogen, und mittlerweile habe ich tatsächlich die Dateien aufgedröselt und in die MySQL Datenbank geschrieben. Einige Probleme habe ich noch nicht in den Griff bekommen, z.b. werden manchmal führende Leerzeichen in die DB geschrieben in das "Züge" Feld. Das sieht dann so aus:
r15ch13's Code wird mittlerweile dafür verwendet, die DB zu füttern. Es steht sogar trim() dort, aber es kommt nichts getrimmtes an, bzw. nur die erste Zeile? ka...
PHP:
public function getMoves() {
return trim($this->moves);
}
Verstehe es nicht, wieso wird kommt das führende Leerzeichen in der DB an?
Wenn r15ch13 nochmal draufschauen könnte wär ich echt glücklich, ich schick ihm nochmal ne PM
Das Problem mit dem führenden Leerzeichen tritt auch manchmal bei den Namen auf, dort ist es noch schlimmer, denn mein Inhaltsverzeichnis ist dann an dieser Stelle kaputt.
Folgende Aenderungen an der Game-Klasse sollten das ganze beheben.
private $moves wird zum Array.
In der addMoves() wird trim() auf den Wert angewendet und fuegt ihn zum Array hinzu.
getMoves() verbindet mit implode() das Array $moves zu einem String.
In der addInfo() wird trim() auf den Wert angewendet. (Behebt " Gheng, Josef")
PHP:
class Game
{
private $info = [];
private $moves = [];
public function __construct()
{
}
public function addInfo($name, $value)
{
$this->info[$name] = trim($value);
return $this;
}
public function getInfo()
{
return $this->info;
}
public function addMoves($moves)
{
$this->moves[] = trim($moves);
return $this;
}
public function getMoves()
{
return implode(" ", $this->moves);
}
}
Das Problem bei den Namen taucht nicht mehr auf, das Inhaltsverzeichnis sieht tadellos aus.
Jetzt habe ich noch etwas modifiziert:
Code:
public function getMoves()
{
return trim(implode(" ", $this->moves));
}
... weil sonst immer ein führendes Leerzeichen in den Zugfeldern stand. Es begann sonst immer mit " 1." statt "1.".
Ok vielen Dank nochmal für Deine mitarbeit und Tips, sollten weitere Probleme auftreten, werde ich Dich wieder anquatschen
Oder ich schreibe das Ding noch einmal selber, da lernt man immer noch am meisten, wenn ich Zeit habe.
Für den Moment sieht es so aus, als liefe es perfekt, aber ich werde weiter testen, bis ich den nächsten Fehler finde
Edit: Und da ist das nächste Problem... bei einem upload sind leere Werte geschrieben worden, jetzt muss ich nur noch die Datei finden, bei der es passiert ist. Vielleicht schreibe ich den Dateinamen einfach mit in die DB, dann kann ich mir das regelmäßige löschen sparen und weiss in welcher Datei ich suchen muss.
Edit2: ok, das war einfach mit dem Dateinamen. Es ist bei dieser Datei aufgetreten http://devphp.de/pgn/pgnfiles2/runde1.pgn
Dort wurden für White, Black, Round, Date etc. "NULL" in die DB geschrieben. Für mich sieht die Datei völlig valide aus. Es wurden lediglich die Züge korrekt geschrieben. Jetzt habe ich wieder einen hässlichen leeren Balken im Inhaltsverzeichnis. Hat jemand eine Idee warum?
Ich traue mich kaum ihn zu posten, weil er so UNGLAUBLICH hässlich ist, aber nun gut, hier ist er:
PHP:
require_once('class.pgn.php');
require_once('class.game.php');
require_once('vendor/autoload.php');
use AmyBoyd\PgnParser\Game;
use AmyBoyd\PgnParser\PgnParser;
$uploaddir = './pgnfiles2/';
if (!file_exists($uploaddir)) {
mkdir($uploaddir, 0777, true);
}
// search for UMLAUTE etc, replace in filename:
$search = array('ä', 'ö', 'ü', 'ß', 'Ä', 'Ö', 'Ü', ' ');
$replace = array('ae', 'oe', 'ue', 'ss', 'Ae', 'Oe', 'Ue', '_');
$filename = basename($_FILES['userfile']['name']);
$filename = str_replace($search, $replace, $filename);
$uploadfile = $uploaddir . $filename;
$maxSize = 2000000;
// function starts here
function write2db($file, $pw, $mail, $name) {
$p = new pgn();
$g = new GameOfPgn();
$games = $g->readGamesFromPgn($file);
$parser = new PgnParser($file);
$gms = 0;
foreach ($games as $gamenum => $game) {
$valuestring = "";
$valuedblstring = "";
$infoValueString = "";
$sureInfo = "";
$sureInfoValue = "";
$sureInfoString = "";
$sureInfoValueString = "";
foreach ($game->getInfo() as $info => $infoValue) {
$newcol = "ALTER TABLE " . $p->filetable . " ADD `" . $info . "` TEXT after `MovesClean`";
try {
if ($p->con->query($newcol)) {
echo("Query was successful ...<br>\n");
} else {
echo("Query wasn't successful, check your script");
}
} catch (Exception $e) {
// echo 'Exception abgefangen: ', $e->getMessage(), "\n";
}
// assemble strings
$valuestring .= $info . ", ";
$valuedblstring .= ":" . $info . ", ";
$infoValue = rtrim($infoValue, "\""); // dirty hack, not a clean solution
$infoValueString .= $infoValue . ", ";
$sureInfo .= $info . "-_-//-_-";
$sureInfoValue .= $infoValue . "-_-//-_-";
}
$gamemov = $parser->getGame($gms);
$serialmoves = serialize($gamemov->getMovesArray());
// insert into DB
// find dubliactes
// try to select
$select = "SELECT * FROM " . $p->filetable . " WHERE MovesClean = :mc";
$stmt = $p->con->prepare($select);
$stmt->bindParam(":mc", $serialmoves);
$stmt->execute();
if ($stmt->rowCount() > 0) {
echo "Identische Partie schon in der Datenbank.<br>\n";
// while ($row = $stmt->fetch()) { echo $row["White"]. " - " . $row["Black"];
// }
} else {
$sureInfo = rtrim($sureInfo, "-_-//-_-");
$sureInfoValue = rtrim($sureInfoValue, "-_-//-_-");
$insert = "INSERT INTO " . $p->filetable . " (" . $valuestring . "Moves, MovesClean, UploadDate, UploadPW, CategoryID, UploadName, UploadEmail, FileName) VALUES (" . $valuedblstring . ":moves, :movesclean, :uploadDate, :uploadPW, :catID, :upname, :upEmail, :file)";
$stmt = $p->con->prepare($insert);
$sureInfoExplode = explode("-_-//-_-", $sureInfo);
$sureInfoValueExplode = explode("-_-//-_-", $sureInfoValue);
$infoexplode = explode(", ", $infoValueString);
foreach ($sureInfoExplode as $key => $val) {
$stmt->bindParam($sureInfoExplode[$key], mb_convert_encoding($sureInfoValueExplode[$key], "UTF-8", mb_detect_encoding($sureInfoValueExplode[$key])));
}
require_once ('../includes/PasswordHash.php');
if ($name == "") {
$name = "NoName";
}
if ($pw == "") {
$pw = "NoPassword";
}
if ($mail == "") {
$mail = "NoEmail";
}
$cat = 0;
$hasher = new PasswordHash(8, FALSE);
$hash = $hasher->HashPassword($pw);
$stmt->bindParam(":moves", $game->getMoves());
$stmt->bindParam(":movesclean", $serialmoves);
$stmt->bindParam(":uploadDate", $p->today);
$stmt->bindParam(":upEmail", $mail);
$stmt->bindParam(":upname", $name);
$stmt->bindParam(":uploadPW", $hash);
$stmt->bindParam(":catID", $cat);
$stmt->bindParam(":file", $file);
$stmt->execute();
echo 'Partie in Datenbank geschrieben.' . "<br>\n";
echo "<hr>";
$gms++;
}
}
echo count($games) . " Spiele in der Datei.";
echo "<br>";
}
// FUNCTION ENDS HERE
// GET VARIABLES OF $_POST
if (!empty($_POST)) {
$pw = filter_input(INPUT_POST, "pass", FILTER_SANITIZE_STRING);
$name = filter_input(INPUT_POST, "name", FILTER_SANITIZE_STRING);
$mail = filter_input(INPUT_POST, "mail", FILTER_SANITIZE_STRING);
}
// ACTUAL UPLOAD STARTS HERE //
if (file_exists($uploadfile)) {
die("Die Datei $uploadfile existiert bereits.");
} else {
$allowedExts = array("pgn");
$temp = explode(".", $_FILES["userfile"]["name"]);
$extension = end($temp);
if (($_FILES["userfile"]["size"] < $maxSize) && in_array($extension, $allowedExts) && ($_FILES["userfile"]["error"] == 0)) {
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
// get content, encode it to UTF8, put content back into file
$file_contents = file_get_contents($uploadfile);
$encoded_content = mb_convert_encoding($file_contents, "UTF-8", mb_detect_encoding($file_contents));
file_put_contents($uploadfile, $encoded_content);
echo("Ihre Datei wurde erfolgreich übertragen.<br>\n");
echo 'Alles unterhalb dieser Zeile sollte für Sie irrelevant sein<br>';
echo'<a href="javascript:history.back()">Zurück</a><br><br>' . PHP_EOL;
write2db($uploadfile, $pw, $mail, $name);
} else {
echo "Dateiupload fehlgeschlagen!\n";
echo $uploadfile;
}
} else {
echo "Dateiupload fehlgeschlagen!\n";
echo("Zulässige Dateigröße überschritten?");
}
}
Er ist sehr hässlich, aber meistens funktioniert er ja. Zum Verständnis:
$sureInfoExplode = explode("-_-//-_-", $sureInfo);
Das "-_-//-_-" habe ich benutzt, weil kommas etc. einfach nicht funktioniert haben. Es musste einfach etwas aussergewöhnliches sein, das sonst nicht in den Dateien vorkommt.
Die class.pgn.php könnte ich auch noch posten bei bedarf, aber dort steht soviel Müll drin, dass ich sie nochmal neu schreiben sollte. Zuerst war das ganze Projekt Dateien-basiert, jetzt ist es MySQL-basiert. In der Zeit hat sich viel "Müll" angesammelt in der Datei.
Die upload2.php könnte auch noch intressant sein, kann ich auch bei bedarf posten.
PasswordHash.php ist die PW-Hash funktion von Drupal, die ich gefunden habe beim stöbern. Funktioniert super.
Der pgn parser von AmyBoyd leistet hervorragende Arbeit bei der Identifizierung von Dublikaten.
Naja, sonst... läuft, ist aber hässlich wie die Nacht
Edit: hier ist das Formular, dass für den upload verantwortlich ist, es könnte helfen...
der Code ist also nicht nur hässlich, sondern auch buggy.
Nunja, immerhin werden einige Felder geschrieben, bei der runde1.pgn wurden nur die Züge geschrieben.
Endless bugfixing
http://www.devphp.de/pgn/openings2.php
Hier ist wieder etwas falsch angekommen, [Event ist kein Zug, aber wohl in das Moves Feld gerutscht.
Ich schreibe demnächst mal eine Seite die mir die fehlerhaften Reihen anzeigt.
Die ./pgnfiles2/9Neckar-Open2005.pgn scheint die größten Probleme zu machen, dort sind auch Reihen ohne "Moves" zu finden.
In diesen Reihen sind aber die anderen Felder ausgefüllt.
Was ich mir dabei gedacht habe, weiss ich selbst nicht mehr. Ich denke, dort habe ich foreach noch nicht wirklich verstanden. $sureInfoExplode[$key] müsste einfach durch $val zu ersetzen sein.
Ich habe hier mal eine .zip zusammengestellt, dann kann man das gesamte Projekt anschauen und testen.
$sel = "SELECT * FROM " . $p->filetable . " WHERE White IS NULL";
$stmt = $p->con->prepare($sel);
$stmt->execute();
echo "<b>".$stmt->rowCount(). " White = NULL</b><br>".PHP_EOL;
while ($row = $stmt->fetch()) {
foreach ($row as $key => $val) {
if ($val != NULL && !is_numeric($key)) {
echo "<b>".$key. "</b> : ".$val."<br>".PHP_EOL;
}
}
echo "<hr>".PHP_EOL;
}
Das sind natürlich nicht alle, nur mit WHITE IS NULL
Intressant ist, dass manche Reihen im Feld "MovesClean" ein gefülltes serialize'd array haben, aber ein leeres "Moves" Feld. "MovesClean" ist das Array von AmyBoyd's pgn parser.
ID : 4433 dort ist ein mismatch zwischen Moves and MovesClean, im Array stehen andere Züge als im Moves.
Aha, das mismatch tritt häufiger auf, auffallend ist auch, dass die IDs immer in 2er Schritten inkrementieren, es scheint, dass dort 2 Reihen geschrieben werden...
http://devphp.de/img/myadmin2.png
Screenshot vom phpmyadmin, nach ID sortiert, jedes 2. Moves ist leer, MovesClean passt nicht zu den Moves... Nur wenige Felder gefüllt.... MovesClean passt weder zur Reihe davor noch danach...
Der Fehler muss in der geposteten Funktion liegen, aber wo genau? Kann ich mir im Moment nicht erklären...
Erstmal: Wow das ist ja ein Chaos! Das musst du unbedingt aufraeumen! Wie waere es mal mit einem Framework? Microframework http://lumen.laravel.com/ oder normales http://laravel.com/
Ich glaube ich habe das Problem gefunden. In der Game-Klasse wird mit strpos($line, '[Event') geprueft ob eine neue Partie anfaengt. Nun gibt es in deinen Dateien auch [EventDate "2005.03.??"] und da wird nun neue Partie angefangen in der dann nur noch SourceDate, Source und die Moves enthalten sind.
Sollte dadurch geloest sein:
PHP:
if(strpos($line, '[Event') !== false)
durch folgendes ersetzen:
PHP:
if (preg_match('/(\[Event "(.*)"\])/', $line)) {
Edit: Und noch eine Aenderung beim erkennen der Partieinformationen.
PHP:
class GameOfPgn {
private $info = [];
private $moves = [];
public function addInfo($name, $value)
{
$this->info[$name] = trim($value);
return $this;
}
public function getInfo()
{
return $this->info;
}
public function addMoves($moves)
{
$this->moves[] = trim($moves);
return $this;
}
public function getMoves()
{
return trim(implode(" ", $this->moves));
}
function readGamesFromPgn($file) {
if (!file_exists($file))
return [];
$content = file_get_contents($file);
$lines = explode("\n", $content);
$games = [];
$game = null;
foreach ($lines as $line) {
// Neues Spiel gefunden
if (preg_match('/(\[Event "(.*)"\])/', $line)) {
if (!empty($game)) {
$games[] = $game;
}
$game = new GameOfPgn();
}
if(preg_match('/(\[(?P<name>.*) "(?P<value>.*)"\])/', $line, $matches)) {
if (!empty($game) && isset($matches['name']) && isset($matches['value'])) {
$game->addInfo($matches['name'], $matches['value']);
}
} else {
if(!empty(trim($line)) && !empty($game))
{
$game->addMoves($line);
}
}
}
if (!empty($game)) {
$games[] = $game;
}
return $games;
}
}
Das ist unglaublich. Das wäre mir in 5 Jahren nicht aufgefallen. Das hätte man auch einfach mit einem zusätzlichen Leerzeichen, statt
PHP:
if(strpos($line, '[Event') !== false)
PHP:
if(strpos($line, '[Event ') !== false)
beheben können. Habe jetzt Deine Zeile genommen und es gibt bisher keine leeren Moves Felder, und keine leeren Werte in den Spalten "White" und "Black".
EINE, Zeile ist mir jedoch aufgefallen, dort steht im Moves Feld folgendes:
In der geposteten Game Klasse ist Dir ein Fehler unterlaufen, in der readGamesFromPgn() gibt es keine $matches. $game->addInfo($matches['name'], $matches['value']) kann also nicht funktionieren. Kein Ahnung wo das her kommt.