2010-07-27 4 views
-1

J'ai eu un peu de mal avec un de mes projets. Comme beaucoup de nerds, j'ai décidé de créer mon propre site d'évaluation de jeux vidéo. Les commentaires sont stockés dans la base de données, et peuvent être récupérées via le titre du jeu avec une URL comme:Gestion du '.' caractère passé à une requête MySQL via url

http://www.example.com/reviews/ {gamename}/{option pageOfReview}

Malheureusement, lors du test de cas de pointe, je suis venu à travers une erreur étrange - si le jeu a une période dans son titre, je ne peux pas le récupérer. Si la période est le caractère principal du titre (comme .hack), j'obtiens un écran d'erreur de trace de la pile Kohana qui me dit que la critique (ou, plus précisément, le jeu) n'existe pas. Si c'est au milieu ou à la fin du titre, je reçois un de mes propres messages d'erreur disant que la révision (jeu) n'a pas pu être récupérée. Y at-il un moyen de contourner cela? Est-ce une question de savoir comment MySQL analyse une période, ou quelque chose d'autre?

EDIT: Toutes les requêtes sont traitées via la fonctionnalité ORM de Kohana 2 à l'aide du pilote MySQLi. Enregistrement d'un examen (contrôleur d'administration):

public function saveReview() 
{ 
    $this->checkAdmin(); 

    if (isset($_POST['submit'])) { $this->storeReview(); } 
    else { header('Location: /admin'); } 
} 

private function storeReview($id = null) 
{ 
    if (!preg_match("/^[a-zA-Z0-9\-_:!'. ]*$/", $_POST['gameTitle']) || empty($_POST['gameTitle'])) { $gameTitle = false; } 
    else { $gameTitle = ucwords($this->clean($_POST['gameTitle'])); } 

    if (!is_numeric($_POST['genre'])) { $genre = false; } 
    else { $genre = $_POST['genre']; } 

    $platformCheckArray = array_map('is_numeric', $_POST['platforms']); 

    $platformCheck = true; 
    foreach ($platformCheckArray as $pca) 
    { 
     if (!$pca) 
     { 
      $platformCheck = false; 
      break; 
     } 
    } 

    $proCheck = true; 
    $cleanedPros = array(); 

    foreach ($_POST['pros'] as $pro) 
    { 
     if (!preg_match("/^[a-zA-Z0-9\-_:!' ]*$/", $pro)) 
     { 
      $proCheck = false; 
      break; 
     } 

     if (!empty($pro)) { $cleanedPros[] = $this->clean($pro); } 
    } 

    $conCheck = true; 
    $cleanedCons = array(); 

    foreach ($_POST['cons'] as $con) 
    { 
     if (!preg_match("/^[a-zA-Z0-9\-_:!' ]*$/", $con)) 
     { 
      $conCheck = false; 
      break; 
     } 

     if (!empty($con)) { $cleanedCons[] = $this->clean($con); } 
    } 

    if (!is_numeric($_POST['score'])) { $score = false; } 
    else { $score = $_POST['score']; } 

    if (empty($_POST['content'])) { $content = false; } 
    else { $content = true; } 

    // save review if all tests pass, display error otherwise 

    if ($gameTitle && $genre && $platformCheck && $proCheck && $conCheck && $score && $content) 
    { 
     $gameTitle = $gameTitle; 
     $platforms = $_POST['platforms']; 
     $reviewContent = $_POST['content']; 
     $prosText = implode(', ', $cleanedPros); 
     $consText = implode(', ', $cleanedCons); 

     $game = ORM::factory('game'); 
     $game->title = $gameTitle; 
     $game->genre_id = $genre; 
     $game->platforms = $platforms; 
     $game->save(); 

     $storedGenre = ORM::factory('genre')->where('id', $genre)->find(); 
     $storedGenre->platforms = $platforms; 
     $storedGenre->save(); 

     $review = ORM::factory('review', $id); 
     $review->content = $reviewContent; 
     $review->score = $score; 
     $review->game_id = $game->id; 
     $review->date_added = date('Y-m-d H:i:s'); 
     $review->platforms = $platforms; 
     $review->save(); 

     $pros = ORM::factory('pro'); 
     $pros->review_id = $review->id; 
     $pros->text = $prosText; 
     $pros->save(); 

     $cons = ORM::factory('con'); 
     $cons->review_id = $review->id; 
     $cons->text = $consText; 
     $cons->save(); 

     if ($game->saved && $storedGenre->saved && $review->saved && $pros->saved && $cons->saved) { $this->success('review'); } 
     else { $this->showError("Something went wrong with saving the review. Please try again."); } 
    } 
    else { $this->showError("All fields must contain values. Please try again."); } 
} 

Récupération d'un examen (du contrôleur de commentaires):

public function show($id, $page = 1) 
{ 
    if (is_numeric($id)) { $game = ORM::factory('game', $id); } 
    else 
    { 
     $id = ucwords(stripslashes($id)); 
     $game = ORM::factory('game')->where('title', $id)->find(); 
    } 

    if ($game->loaded) { $this->showReview($game->id, $page); } 
    else { HandiError::factory('Could not retrieve the specified review. Please check that you entered the correct value.'); } 
} 

private function showReview($id, $page = 1) 
{ 
    $page = (int)$page; 

    if ($page < 1) { $page = 1; } 

    if ($id) 
    { 
     $game = ORM::factory('game', $id); 
     $review = ORM::factory('review')->where('game_id', $game->id)->find(); 
     $genre = ORM::factory('genre')->where('id', $game->genre_id)->find(); 
     $revPlatforms = $this->db->query("SELECT * FROM platforms 
             INNER JOIN platforms_reviews AS pr ON platforms.id = pr.platform_id 
             INNER JOIN reviews ON pr.review_id = reviews.id 
             WHERE reviews.id = ?", $review->id); 
     $revPros = ORM::factory('pro')->where('review_id', $review->id)->find(); 
     $revCons = ORM::factory('con')->where('review_id', $review->id)->find(); 

     $platforms = array(); 
     foreach($revPlatforms as $rp) { $platforms[] = $rp->name; } 
     $pros = explode(', ', $revPros->text); 
     $cons = explode(', ', $revCons->text); 

     $pages = explode('&lt;split /&gt;', $review->content); 
     $count = count($pages); 

     if ($page > ($count)) { $content = $pages[0]; } 
     else { $content = $pages[$page - 1]; } 

     $view = new View('reviews/show_review'); 
     $view->content = $content; 
     $view->gameTitle = $game->title; 
     $view->genre = $genre->name; 
     $view->platforms = implode(', ', $platforms); 
     $view->pros = $pros; 
     $view->cons = $cons; 
     $view->score = $review->score; 
     $view->pages = $pages; 
     $view->render(true); 
    } 
    else { HandiError::factory('Could not retrieve the specified review. Please check that you entered the correct value.'); } 
} 

EDIT 2: Eh bien, j'ai découvert quelque chose sur le principal cas de période:

Dans l'index de mon contrôleur, j'ai quelques requêtes que j'utilise pour lister les critiques par titre de jeu, plateforme, genre, etc. C'est en gros un wiki de pauvre. Voir:

public function index() 
{ 
    /* show a wiki-like page with reviews listed by title, 
    * game title, genre, and platform 
    */ 

    $numGenres = $this->db->query("SELECT COUNT(id) AS num FROM genres"); 
    $numPlatforms = $this->db->query("SELECT COUNT(id) AS num FROM platforms"); 

    $genreCount = $numGenres[0]->num; 
    $platformCount = $numPlatforms[0]->num; 
    $scoreCount = 5; 

    $genreResults = array(); 
    $platformResults = array(); 
    $scoreResults = array(); 

    $gameResults = $this->db->query("SELECT LEFT(title, 1) AS letter, COUNT(id) AS count FROM games GROUP BY letter ORDER BY letter ASC"); 

    for($i = 1; $i < ($genreCount + 1); ++$i) 
    { 
     $genreResults[] = $this->db->query("SELECT genres.id AS id, genres.name AS name, COUNT(reviews.id) AS num FROM reviews 
              INNER JOIN games ON reviews.game_id = games.id 
              INNER JOIN genres ON games.genre_id = genres.id 
              WHERE genres.id = ?", $i); 
    } 

    for($j = 1; $j < ($platformCount + 1); ++$j) 
    { 
     $platformResults[] = $this->db->query("SELECT platforms.id AS id, platforms.name AS name, COUNT(reviews.id) AS num FROM reviews 
               INNER JOIN platforms_reviews AS pr ON reviews.id = pr.review_id 
               INNER JOIN platforms ON pr.platform_id = platforms.id 
               WHERE platforms.id = ?", $j); 
    } 

    for($k = 1; $k < ($scoreCount + 1); ++$k) 
    { 
     $scoreResults[] = $this->db->query("SELECT score, COUNT(id) AS num FROM reviews WHERE score = ?", $k); 
    } 

    $view = new View('reviews/index'); 
    $view->gamesByLetter = $gameResults; 
    $view->genres = $genreResults; 
    $view->platforms = $platformResults; 
    $view->scores = $scoreResults; 
    $view->render(true); 
} 

Quand je passe les résultats de ces requêtes à la vue, je boucle à travers eux et créer des liens basés sur la catégorie méta. Ainsi, il montre combien de jeux commencent par la lettre A, B, etc., et en cliquant sur l'un de ces liens, l'utilisateur accède à une liste de liens, chacun avec une critique (So, A-> Afterburner (entre autres) -> commentaire pour Afterburner).

Lorsque je souris sur le groupe qui a la période principale, ma barre d'état indique que la période est manquante dans le lien, même si elle apparaît dans la source. Ainsi, même si la source montre le lien comme site.com/reviews/game/. le navigateur le montre comme site.com/reviews/game/ Cela me fait croire que la période n'est même pas passée dans la méthode, et la trace de la pile semble confirmer (elle prétend qu'il y a un argument manquant, qui serait la période).

EDIT 3: Bon, j'ai jeté un coup d'œil à mes routes, et je n'y trouve rien. Cela dit, j'ai un fichier .htaccess qui mod_rewrites les routes à regarder pour SEO, donc je me demande si cela pourrait être le problème. Je n'ai jamais écrit un fichier mod_rewrite moi-même - les gens sur les forums Kohana m'ont donné ceci, et cela a fonctionné, alors je suis allé avec. Je peux comprendre certains des regEx impliqués, mais mon regEx Fu est faible. Je crois que la dernière ligne fait la 'magie'.

# Turn on URL rewriting 
Options +FollowSymlinks 
RewriteEngine On 

# Put your installation directory here: 
# If your URL is www.example.com/, use/
# If your URL is www.example.com/kohana/, use /kohana/ 
RewriteBase/

# Do not enable rewriting for files or directories that exist 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 

# For reuests that are not actual files or directories, 
# Rewrite to index.php/URL 

# Original rule: 
# RewriteRule ^(.*)$ index.php/$1 [PT,L] 

# Alternative rule: 
# RewriteRule .* index.php/$0 [PT,L] 

# 2nd alternative rule that works on ICDSoft: 
RewriteRule .* index.php?kohana_uri=$0 [PT,QSA,L] 

Si je lis bien, le '.' signifie simplement un seul caractère.

Est-ce qu'un '.' être utilisé dans une URL bien formée en dehors de l'endroit où il indique une extension de fichier ou un suffixe Web (.com, .org, etc.)? Je veux dire, ils n'apparaissent pas dans la barre d'état de Firefox lorsque je survole un lien avec eux, ce qui me porte à croire qu'il s'agit d'un problème de navigateur/de forme, pas codé.

+0

Pouvez-vous poster la requête que vous utilisez pour récupérer l'article? Le code PHP serait utile, et si possible, un echo/print de l'instruction finale avant qu'il ne soit envoyé à MySQL. – Mike

+0

Je n'utilise pas Kohana - est-ce que la trace de la pile contient (ou peut) la requête SQL qui cause le problème? – Mike

+0

D'après ce que je peux voir, non. –

Répondre

0

le temps de vérifier toutes les requêtes générées par Profiler.

dans le contrôleur :: __ construct() a mis

nouveau Profiler;

et trouver la requête éventuellement brisée.

Autre solution possible: votre code Go cuvette, parfois non fermé/base de données instance de requête non terminée peut cassé (ou fusionné) autre requête ...

0

MySQL n'a aucun problème avec les points dans les données de colonne.Toutefois, la période est utilisée pour séparer les noms de tables des noms de colonnes: table.column. Si vos requêtes ne sont pas correctement échappées et entre guillemets, la période peut être interprétée de manière incorrecte comme un séparateur de table/colonne.

Comment préparez-vous vos requêtes?

0

Je pense que ce problème est dans le framework Kohana, pas dans SQL. Chcek pour filtrer les paramètres de l'URL. Essayez d'imprimer votre requête et de voir à quoi elle ressemble exactement au moment où elle va être exécutée, et regardez ce qui s'est passé avec vos règles.

0

EDIT: Désolé, je ne vous ai pas vu utiliser Kohana version 2.x. Je doute que cela s'applique à vous.

Juste une supposition, mais avez-vous défini votre itinéraire pour permettre des périodes dans l'URL? Par défaut, Kohana n'autorise pas les périodes. Vous devrez définir le troisième argument de la Route :: set() à quelque chose comme ceci:

Route::set('reviews', 'reviews/<name>(/<page>)', array('name' => '[^/,;?]++', 'page' => '\d+') 
    ->defaults(array(
     'controller' => 'reviews', 
     'action'  => 'load', 
     'name'  => NULL, 
     'page'  => 1, 
    )); 

Voir post sur le forum http://forum.kohanaframework.org/comments.php?DiscussionID=4320

Questions connexes