Paging - del 2

Publicerat: 2013-11-18 16:31:27 | Kategori: PHP & SQL


För drygt ett halvår sedan gjorde jag ett inlägg om paging och först nu så har jag äntligen optimerat koden för att fungera bättre och vara mer anpassat för en blogg. Det stora problemet med den gamla koden var faktiskt att den endast var tillämpad för inläggen på förstasidan. Går man in på en specifik kategori med fler än 10 inlägg så finns det en länk till nästa sida längst ner, men om man trycker på länken kommer man till sida två från förstasidan. Detta är relativt enkelt att fixa med ett "if"-kommando och "$_Get()" enligt nedan.

if (isset($_GET['kategori'])) {
echo "kategori=$_GET[kategori]&";
} else if (isset($_GET['arkiv'])) {
echo "arkiv=$_GET[arkiv]&";                            
} else if (isset($_GET['search'])) {
echo "search&";
}

Däremot så kommer detta ännu ge resultaten i sidor som ett, två, tre och så vidare. Jag vill påstå att detta ser ut som rent 90-tal om det nu inte skulle handla om ett forum. Tittar man på valfri blogg på nätet så är det mycket vanligare med en länk till äldre och nyare inlägg. Detta gör det enklare för besökaren även om det kanske inte ger lika mycket valfrihet.

För att få fram antalet sidor använder jag i princip samma kod som i tidigare inlägg, men vissa små korrigeringar har gjorts för att endast räkna publicerade inlägg.

$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
if (!isset($_GET['id'])) {   
  $pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts WHERE $publicerat $sql_statement")));
}
$pages = ceil($pages / 10);
$querystring = "";
  foreach ($_GET as $key => $value) {
    if ($key != "page") $querystring .= "$key=$value&";
 }

De i röd text får bytas ut mot egen kod, tabeller och rader.

För att ta fram inläggen så är det i princip även här ungefär samma kod, men den har optimerats betydligt sedan förra inlägget.

$sql = "SELECT * FROM posts WHERE $publicerat $sql_statement ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $sql);

while ($row = mysqli_fetch_assoc($result)) { 

Text,,,

}

Det har skett ofantligt mycket där sidlänkarna visas däremot. Kort och gott så fick jag ändra på hela koden, men på något otroligt vis fick jag det att fungera. Det är inte som att det gick att googla efter andra som delat med sig av liknande kod för det verkar inte alls finnas!

Nedan följer en helt oförändrad kod från min blogg för hur koden för äldre och nyare inlägg visas och länkas.

                  if (($_GET['page'] > 1)) {
                        echo "<a class='div_post_2' href='index.php?";
                        
                            if (isset($_GET['kategori'])) {
                            echo "kategori=$_GET[kategori]&";
                            } else if (isset($_GET['arkiv'])) {
                            echo "arkiv=$_GET[arkiv]&";
                            } else if (isset($_GET['search'])) {
                            echo "search&";
                            }
                        
                        echo "page=";
                            if (isset($_GET['page'])) {
                                echo $_GET['page'] - 1;
                                }
                        echo "'>Nyare inl&auml;gg &raquo;&raquo;</a>";
                    }
        
          if (!($_GET['page'] >= $pages)) {
                        echo "<a class='div_post_1' href='index.php?";
                        
                        if (isset($_GET['kategori'])) {
                            echo "kategori=$_GET[kategori]&";
                            } else if (isset($_GET['arkiv'])) {
                            echo "arkiv=$_GET[arkiv]&";                            
                            } else if (isset($_GET['search'])) {
                            echo "search&";
                            }
                        
                        echo "page=";
                            if (!isset($_GET['page'])) {
                                echo 2;
                            } else {
                                echo $_GET['page'] + 1;
                                }
                        echo "'>&laquo;&laquo; &auml;ldre inl&auml;gg</a>";
                    }

Det blev en hel del text för något väldigt litet! Koden går säkert att optimera något, men det var nog tidskrävande för mig att skriva en helt ny kod som fungerar. cheeky


Kommentera

SQL-kod för arkiv

Publicerat: 2013-05-04 21:56:17 | Kategori: PHP & SQL

Kvällens stora uppdatering var som sagt ett bloggarkiv. I min databas så läggs en tidsstämpel till automatiskt när jag skrivit ett inlägg. Det är i "CURRENT_TIMESTAMP" som är formaterat som "0000-00-00 00:00:00". Det är väldigt passande för att visa i inlägg, men är inte sådär jätteanpassat för ett arkiv. Utmaningen var alltså att konvertera om tidsstämpeln till månad och år.

Det finns många sätt att lösa det med, men i mitt fall valde jag att göra det endast med sql. För att visa månad och år i menyn användes följande:

$sql = "SELECT DISTINCT DATE_FORMAT(datum, '%M %Y') AS 'month', DATE_FORMAT(datum, '%M-%Y') AS 'month2' FROM posts ORDER BY datum DESC";

För att översätta till svenska blir det ungefär "välj unika datum formaterade i månad och år och kalla det för månad". I princip gör den samma sak två gånger just nu. En gång för att visa och en gång för att skapa en länk. Det hade varit bättre att lägga till ett streck med en str_replace i php, men jag ville bara få det löst så fort som möjligt. :)

För att visa inläggen för den aktuella månaden och året så krävs det ytterligare en kodsnutt:

$sql = "SELECT * FROM posts WHERE DATE_FORMAT(datum, '%M-%Y') = '$search_archive' ORDER BY datum DESC";

Här väljer databasen ut månad-år och jämför det med $search_archive som i detta fallet är $_GET-värdet från länken som skapades högre upp.

 

Uppdatering 2013-05-04
Något som slog mig häromdagen är att MySQL faktiskt visar månaderna på engelska vilket är ett litet problem om man har en hemsida på svenska vilket är fallet här. Ett enkelt sätt att lösa detta på är att sätta upp en array och översätta med preg_replace. Först och främst så behöver vi inte översätta alla månader, endast hälften skiljer sig. Vi sätter först upp en enkel array och skriver de engelska namnen på månaderna.

$patterns = array('/January/', '/February/', '/March/', '/May/', '/June/', '/July/', '/October/'); 

Efter detta så måste vi skapa ännu en array med de svenska namnen.

$replacements = array('Januari', 'Februari', 'Mars', 'Maj', 'Juni', 'Juli', 'Oktober'); 

Nu gäller det bara att koppla ihop dem med en preg_replace.

$timestamp2 = preg_replace($patterns, $replacements, $timestamp); 

$timestamp i detta fall är vad som tas ut ur databasen och formaterats om med date_format. Om inte preg_replace hittar ett ord från $patterns så kommer det inte att ändras, t ex "april". Om däremot ordet i $patterns skulle hittas så letar preg_replace upp översättningen i $replacements.

Det här fungerar såklart inte bara för månader, även dagar eller i princip vad som helst kan översättas på samma sätt.


Kommentera

Paging och optimering

Publicerat: 2013-04-29 22:38:20 | Kategori: PHP & SQL

Tro det eller ej, men paging kan vara förbaskat knepigt att få till även på ett mindre projekt. När jag tidigare skrev om att kommentarssystemet var komplext hade jag nog inte riktigt tänkt på paging. Det finns hundratals sätt olika människor har löst det på, det ena klurigare än det andra. Testa bara att googla på simpla paging-skript, det är skrämmande vad folk tycker är enkelt egentligen!

Det som gör det knepigt är egentligen inte att skriptet är långt eller invecklat i sig, men att man måste bädda in det så utomordenligt perfekt i sin egna applikation för att det ska fungera. Det krävs således att man förstår skriptet till punkt och pricka och är det då ett så kallat "enkelt skript" med "endast" 50 rader kod så är det plötsligt en mardröm. Jag hittade till slut en blogg med ett så pass enkelt paging-skript att det faktiskt gick att förstå. Ändå tog det åtskilliga timmar att konvertera php-filen för inlägg.

Här kommer ett exempel på hur sökning fungerade på hraffe.se:

$sql = "SELECT * FROM posts WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%' ORDER BY datum DESC LIMIT 10";

I princip alla databasfunktioner hade ett liknande utseende. När paging kommer in i bilden så blir plötsligt en hel del kod att blanda in i det hela. Utan optimering skulle sökningen plötsligt se ut så här:

$pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%'")));

$sql = "SELECT * FROM posts WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%' ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";

Utan att överdriva så är det väldigt mycket kod för att endast vara SQL! Med PHP och alla IF/ELSE så blir det fort mycket svårt att hålla reda på. Det jag gjorde var att jag klurade ut ett sätt så strängarna utbyter information. Detta är egentligen inte så avancerat, men absolut ingenting jag tänkte på:

$sql_statement = "WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%'";

 $pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts $sql_statement")));

$sql = "SELECT * FROM posts $sql_statement ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";

Till synes är det mer kod, men i längden blir det mindre. $sql_statement bestämmer vad SQL-kommandot ska göra och det betyder att man med några IF/ELSE helt enkelt kan bestämma vad som ska visas på sidan. Vi kör med ännu ett exempel på hur sidan skulle se ut utan $sql_statement:

if (isset($_GET['search'])) { 
$pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%'")));

$sql = "SELECT * FROM posts WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%' ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";

} else if 
(isset($_GET['kategori'])) {
$pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts WHERE kategori LIKE '%$search_kategori%'";

$sql = "SELECT * FROM posts WHERE kategori LIKE '%$search_kategori%'  ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10"; 

} else if (isset($_GET['arkiv'])) {
$pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts  
WHERE DATE_FORMAT(datum, '%M-%Y') = '$search_archive'";

$sql = "S
ELECT * FROM posts WHERE DATE_FORMAT(datum, '%M-%Y') = '$search_archive'  ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";
}

Det är en enda stor röra som faktiskt går att förenkla enormt även om man inte först tänker på det. Med $sql_statement som jag la till skulle denna röra bli:

if (isset($_GET['search'])) {
$sql_statement = "WHERE rubrik LIKE '%$search_string%' OR kategori LIKE '%$search_string%' OR text LIKE '%$search_string%'";

} else if (isset($_GET['kategori'])) {
$sql_statement = "WHERE kategori LIKE '%$search_kategori%'";

} else if (isset($_GET['arkiv'])) {
$sql_statement = "WHERE DATE_FORMAT(datum, '%M-%Y') = '$search_archive'";
}

$pages = implode(mysqli_fetch_assoc(mysqli_query($GLOBALS["___mysqli_ston"], "SELECT COUNT(id) FROM posts $sql_statement")));

$sql = "SELECT * FROM posts $sql_statement ORDER BY datum DESC LIMIT " . (($page - 1) * 10) . ", 10";

Plötsligt så är koden på hela sidan betydligt förenklad och ger mycket mer överblick! Det är precis såhär man måste tänka när man kodar en hemsida. Jag vet inte hur andra tänker, men själv så har jag tidigare lagt krutet på att optimera PHP-koden och lämnat SQL-strängarna orörda.

Det här är alltså verkligen inte en guide till hur paging fungerar, men hur man ska tänka och hur man ska få det lättare att tillämpa paging. Jag rekommenderar att titta på Aspektas blogg för att hitta koden jag utgick ifrån.


Kommentera

MySQL till MySQLi

Publicerat: 2013-04-24 17:51:58 | Kategori: PHP & SQL

För endast några dagar sedan så uppmärksammade jag att MySQLi eller "MySQL improved" är en ny standard mer eller mindre. Detta lät väldigt intressant och jag valde att läsa vidare och googla runt lite på ämnet. Många verkar ha haft problem att konvertera sina sidor, men jag märkte fort att det nog är bland det enklaste man kan göra. Det går lätt att göra manuellt genom att söka reda på motsvarigheterna mellan standarderna. Inte blir det knepigare av att de oftast heter samma sak i princip, t ex "mysql_fetch_assoc" och "mysqltng_fetch_assoc". Jag hittade även en enkel guide med de flesta skillnaderna.

Även om det är ganska enkelt så finns det ett betydligt enklare alternativ... "MySQL ext/mysq Converter Tool​"! Det är Oracles egna konverteringsskript som helt enkelt gör hela processen mer eller mindre automatisk. Jag konverterade hraffe.se fort och lätt med skriptet och ingenting kan ju egentligen gå fel om man har sparat en backup.

Det är enklast att köra skriptet lokalt på sin egen dator så man slipper problem med rättigheter till mappar och allt vad det kan vara. För att göra det så laddar man ner zip-filen härifrån och packar upp den i www-mappen.

För att förenkla läget avsevärt rekommenderar jag att man kopierar mappen man vill konvertera till "MySQLConverterToolGUI​".

För att sedan starta skriptet så öppnar man valfri webbläsare och går till "http://localhost/MySQLConverterTool/GUI/" eller var det nu installerades. Nu är det mesta en barnlek och det är bara att följa instruktionerna. Först får man välja om man vill konvertera en mapp, en fil eller bara en kodsträng. Har man en stor sajt så är det klart man väljer det första alternativet.

Nästa steg är att skriva in vilken mapp man vill konvertera. Det bästa hade ju varit om man kunde skriva in hela adressen med localhost, men det verkar vara i relation till själva skriptet. På grund av detta är det absolut lättast att som innan rekommenderat att kopiera mappen man vill konvertera till GUI-mappen.

När det kommer till filändelser är det bara att lägga till de som saknas. Frågan om att uppdatera filerna ska man såklart svara ja på. Krysslådan om man vill spara en bakup är egentligen ganska onödig att ha ikryssad om man redan har kopierat mappen med allt innehåll. Sen är det bara att starta!

Det man bemöts av nu är hur konverteringen gick. Några varningar kan man vänta sig, men det är först när man får ett riktigt "error" som det är något som har gått helt åt fanders. I mitt fall klarade jag mig med två relativt snälla varningar om att skriptet inte riktigt förstod sig på min kod. I vilket fall är nästa steg att testa att gå in på hemsidan och surfa runt lite! Med lite tur så fungerar precis allting och då behöver man inte göra mer. Ifall det är något som har gått fel så vet man i och med rapporten i skriptet precis var som felet ligger. För att avhjälpa det specifika problemet rekommenderar jag Googlesmiley


Kommentera