php - Handling the '.' character passed to a MySQL query via url -
i've hit bit of snag 1 of projects. lot of nerds, decided create own video game review site. reviews stored in database, , can retrieved via title of game url like:
http://www.example.com/reviews/{gamename}/{optional pageofreview}
unfortunately, when testing edge cases, came across odd error - if game has period in title can't retrieve it. if period leading character of title (like .hack), kohana stack trace error screen telling me review (or, more accurately, game) doesn't exist. if it's in middle or end of title, 1 of own error messages saying review (game) not retrieved. there way around this? issue of how mysql parses period, or else?
edit: queries handled via kohana 2's orm functionality using mysqli driver. saving review (admin controller):
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 $pca) { if (!$pca) { $platformcheck = false; break; } } $procheck = true; $cleanedpros = array(); foreach ($_post['pros'] $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'] $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 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 saving review. please try again."); } } else { $this->showerror("all fields must contain values. please try again."); } }
retrieving review (from reviews controller):
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 specified review. please check entered 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 * platforms inner join platforms_reviews pr on platforms.id = pr.platform_id inner join reviews on pr.review_id = reviews.id 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 $rp) { $platforms[] = $rp->name; } $pros = explode(', ', $revpros->text); $cons = explode(', ', $revcons->text); $pages = explode('<split />', $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 specified review. please check entered correct value.'); } }
edit 2: well, found out leading period case:
in controller's index, have few queries use list reviews game title, platform, genre, etc. it's poor man's wiki. see:
public function index() { /* show wiki-like page reviews listed title, * game title, genre, , platform */ $numgenres = $this->db->query("select count(id) num genres"); $numplatforms = $this->db->query("select count(id) num 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) letter, count(id) count games group letter order letter asc"); for($i = 1; $i < ($genrecount + 1); ++$i) { $genreresults[] = $this->db->query("select genres.id id, genres.name name, count(reviews.id) num reviews inner join games on reviews.game_id = games.id inner join genres on games.genre_id = genres.id genres.id = ?", $i); } for($j = 1; $j < ($platformcount + 1); ++$j) { $platformresults[] = $this->db->query("select platforms.id id, platforms.name name, count(reviews.id) num reviews inner join platforms_reviews pr on reviews.id = pr.review_id inner join platforms on pr.platform_id = platforms.id platforms.id = ?", $j); } for($k = 1; $k < ($scorecount + 1); ++$k) { $scoreresults[] = $this->db->query("select score, count(id) num reviews score = ?", $k); } $view = new view('reviews/index'); $view->gamesbyletter = $gameresults; $view->genres = $genreresults; $view->platforms = $platformresults; $view->scores = $scoreresults; $view->render(true); }
when pass results of queries view, loop through them , create links based on meta category. so, shows how many games start letter a, b, etc., , clicking on 1 of links brings user list of links, each 1 review (so, a->afterburner (among others)->review afterburner).
when mouse on group has leading period, status bar shows period missing link, though shows in source. so, though source shows link site.com/reviews/game/. browser shows site.com/reviews/game/ makes me believe period isn't being passed method, , stack trace seems confirm (it claims there's missing argument, period).
edit 3: okay, took @ routes, , can't find there. said, have .htaccess file mod_rewrites routes pretty seo, i'm wondering if problem. i've never written mod_rewrite file myself - people on kohana forums gave me this, , worked, went it. can understand of regex involved, regex fu weak. believe last line 'magic'.
# turn on url rewriting options +followsymlinks rewriteengine on # put installation directory here: # if url www.example.com/, use / # if url www.example.com/kohana/, use /kohana/ rewritebase / # not enable rewriting files or directories exist rewritecond %{request_filename} !-f rewritecond %{request_filename} !-d # reuests not actual files or directories, # rewrite index.php/url # original rule: # rewriterule ^(.*)$ index.php/$1 [pt,l] # alternative rule: # rewriterule .* index.php/$0 [pt,l] # 2nd alternative rule works on icdsoft: rewriterule .* index.php?kohana_uri=$0 [pt,qsa,l]
if i'm reading right, '.' means single character.
can '.' used in well-formed url aside denotes file extension or web suffix (.com, .org, etc.)? mean, aren't appearing in firefox's status bar when hover on link them, leads me believe it's browser/well-formedness issue, not coding one.
time check generated queries profiler.
in controller::__construct() put
new profiler;
and find possibly broken query.
other possible solution: go trough code, sometime un-closed/un-terminated database query instance may broke (or merged) other query...
Comments
Post a Comment