Ten artykuł jest archiwalny, korzystasz z niego na własną odpowiedzialność.

System podstron w PHP

Początkujący webmasterzy bardzo często korzystają z takiego kodu:

<?php
$id = $_GET['id'];
if(file_exists($id.'.php')) {
    include $id.'.php';
} else {
    include 'glowna.php';
}
?>

Jest to bardzo proste rozwiązanie. W adresie np. index.php?id=omnie sprawdzamy czy istnieje plik omnie.php i go includujemy, w przeciwnym wypadku zostaje załączony plik glowna.php. Proste, łatwe i szybkie. No ale jest jeden problem... bezpieczeństwo. Wystarczy wpisać w adresie index.php?id=config i mamy hasła i co nam tam sie podoba.

Jest również wersja całkowicie bezpieczna ale trzeba ręcznie wpisywać wszystkie podstrony:

<?php
echo '<a href="index.php">Home</a><br>';
echo '<a href="index.php?page=kontakt">Kontakt</a><br>';
echo '<a href="index.php?page=omnie">O mnie</a><br>';
 
switch($_GET['page']) {
    case 'kontakt':
        include 'kontakt.php';
    break;
 
    case 'omnie':
        echo 'Coś o mnie';
    break;
 
    default:
        include 'glowna.php';
}
 
?>

Jak widać kod też jest prosty. Nic trudnego ;)

No ale my byśmy chcieli pójść krok do przodu... zrobimy panel administratora! Całość będzie się opierała na tabeli w MySQL. Tak więc najpierw ją stworzymy:

CREATE TABLE `strony` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tytul` varchar(255) NOT NULL,
  `tresc` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM;

Standardowa tabela z unikalnym ID, tytułem i treścią.

Jeśli stworzyliśmy już tabelę w bazie danych czas zrobić plik strony.class.php. To plik w którym będą trzymane wszystkie funkcje klasy Strony.

<?php
 
class Strony {
 
    // Hasło do panelu admina
    private $haslo = 'haslo123';
 
    // Host bazy danych
    private $dbhost = 'localhost';
 
    // Użytkownik bazy danych
    private $dbuser = 'root';
 
    // Hasło do bazy danych
    private $dbpass = '';
 
    // Nazwa bazy danych
    private $dbname = 'test';
 
    function __construct() {
        mysql_connect( $this->dbhost, $this->dbuser, $this->dbpass ) or die(mysql_error());
        mysql_select_db( $this->dbname ) or die(mysql_error());
        mysql_query("SET NAMES utf8");
        mysql_query("SET CHARACTER SET utf8");
        mysql_query("SET collation_connection = utf8_polish_ci");
    }
 
    function __destruct() {
        mysql_close();
    }
 
    // inne funkcje
}
 
?>

W powyższym kodzie stworzyliśmy klasę Strony wraz z prywatnymi zmiennymi (co one przechowują jest opisane w komentarzach). Dodatkowo w konstruktorze klasy jest połączenie z bazą danych. Przy połączeniu ustawiamy kodowanie na UTF-8 gdyż jest ono bardzo zalecane i będziemy z niego korzystać w tym tutorialu. W destruktorze rozłączamy się z bazą danych. Tam gdzie jest zaznaczone komentarzem będziemy wklejać inne funkcje.

Przy okazji chciałbym polecić program Notepad++ który wspiera kodowanie UTF-8 :) Program jest po polsku

Tak więc połączenie z bazą danych już mamy to teraz wyświetlimy sobie listę stron:

  function lista() {
        $result = mysql_query("SELECT id, tytul FROM strony ORDER BY id DESC"); // 1
        if(mysql_num_rows($result) > 0) { // 2
            while($row = mysql_fetch_array($result)) { // 3
                echo '<a href="index.php?page='.$row['id'].'">'.$this->stripslashes_deep($row['tytul']).'</a><br>'; // 4
            }
        } else {
            echo '<p>Brak stron!</p>';
        }
    }
  1. Standardowe zapytanie do bazy danych. Pobieramy ID i tytuł sortując wg ID zaczynając od największego.
  2. Jeśli zapytanie zwróciło jakieś wyniki.
  3. Wyświetlamy je w pętli while.
  4. Tworzymy odsyłacz do strony. Korzystamy z funkcji stripslashes_deep którą podam na końcu. Jest to to samo co zwykłe stripslashes z tym że obsługuje tablice.

Teraz funkcja pokazująca stronę:

  function pokaz($id) {
        $row = $this->strona($id);
        echo '<h2>'.$row['tytul'].'</h2>';
        echo '<p>'.$row['tresc'].'</h2>';
    }

Kod bardzo prosty. Pobieramy dane o stronie do tablicy $row. Tytuł wyświetlamy w nagłówku h2 a treść w paragrafie.

Następnie funkcja potrzebna żeby działała powyższa czyli strona()

  function strona($id) {
        $id = (int)$id; // 1
        $result = mysql_query("SELECT * FROM strony WHERE id = '$id'"); // 2
        if(mysql_num_rows($result) > 0) { // 3
            $row = mysql_fetch_array($result); // 4
            return $this->stripslashes_deep($row); // 5
        } else {
            echo '<p>Taka strona nie istnieje!</p>';
            return false; // 6
        }
    }
  1. Rzutujemy ID na liczbę (zabezpieczenie).
  2. Tworzymy zapytanie na stronę z podanym ID.
  3. Jeśli wynik zwrócił jakieś dane...
  4. Pobieramy je do tablicy asocacyjnej.
  5. I zwracamy wyniki przekonwertowane przez funkcję stripslashes_deep.
  6. Jeśli taka strona nie istnieje wyświetlamy komunikat i zwracamy nieprawdę (false).

To by było tyle funkcji wyświetlających. Teraz czas na panel administratora.

  function admin() {
        if(!isset($_SESSION['admin']) || $_SESSION['admin'] != true) {
            $this->admin_logowanie();
            return;
        }
        switch($_GET['akcja']) {
            case 'dodaj':
                $this->admin_dodaj();
            break;
 
            case 'edytuj':
                $this->admin_edytuj($_GET['id']);
            break;
 
            case 'usun':
                $this->admin_usun($_GET['id']);
            break;
 
            default:
                $this->admin_lista();
        }
    }

Funkcja bardzo prosta. Na początek sprawdzamy czy użytkownik jest zalogowany i jesli nie to wywołujemy funkcję admin_logowanie(). Następnie zależnie od akcji w adresie wywołujemy przypisane funkcje. Domyślnie jest to lista wszystkich stron.

  function admin_logowanie() {
        if(isset($_POST['haslo'])) {
            if($_POST['haslo'] == $this->haslo) $_SESSION['admin'] = true;
            else echo '<p>Hasło niepoprawne!</p>';
        }
 
        if(!isset($_SESSION['admin']) || $_SESSION['admin'] != true) {
            echo '<form action="" method="POST">
                    <label>Hasło:</label><br>
                    <input type="password" name="haslo"><br>
                    <input type="submit" value="Zaloguj">
                </form>';
        } else {
            echo '<p>Jesteś zalogowany! <a href="admin.php">Przejdź do strony głównej</a>.';
        }
    }

Funkcja na logowanie. Myślę że jest bardzo prosta i nie wymaga komentarza.

  function admin_lista() {
        $result = mysql_query("SELECT id, tytul FROM strony ORDER BY id DESC");
        if(mysql_num_rows($result) > 0) {
            echo '<table>';
            while($row = mysql_fetch_array($result)) {
                echo '<tr>
                        <td>'.$this->stripslashes_deep($row['tytul']).'</td>
                        <td>
                            <a href="admin.php?akcja=edytuj&id='.$row['id'].'">Edytuj</a> |
                            <a href="admin.php?akcja=usun&id='.$row['id'].'">Usuń</a>
                        </td>
                    </tr>';
            }
            echo '</table>';
        } else {
            echo '<p>Brak stron!</p>';
        }
        echo '<p><a href="admin.php?akcja=dodaj">Dodaj nową stronę</a></p>';
    }

Funkcja bardzo podobna do funkcji lista() z tym że wyniki są wyświetlane w tabeli wraz z linkami do edycji i usuwania. Na dole link do dodawania nowej strony.

Funkcja na dodawanie strony:

  function admin_dodaj() {
        if(isset($_POST['tytul']) && isset($_POST['tresc'])) { // 1
            $tytul = $this->czysc($_POST['tytul']);
            $tresc = $this->czysc($_POST['tresc']); // 2
            $result = mysql_query("INSERT INTO strony (`tytul`, `tresc`) VALUES ('$tytul', '$tresc')"); // 3
            if($result) {
                $id = mysql_insert_id();
                echo '<p>Dodano poprawnie! <a href="index.php?page='.$id.'">Przejdź do strony</a></p>'; // 4
            }
        } else { // 5
            echo '<form action="" method="POST">
                    <label>Tytuł:</label><br>
                    <input type="text" name="tytul" style="width:500px"><br>
                    <label>Treść:</label><br>
                    <textarea style="width:500px" rows="10" name="tresc" id="tresc"></textarea>
                    <input type="submit" value="Wyślij">
                </form>';
        }
    }
  1. Jeśli jest podany tytuł i treść.
  2. Czyścimy zmienne funkcją czysc() która dodaje slashe do ` i ' - aby nam się nie psuło zapytanie.
  3. Wykonujemy zapytanie na dodawanie rekordu.
  4. Jeśli zapytanie przebiegnie poprawnie to pobieramy ID dodanej strony i wyświetlamy do niej link wraz z stosownym komunikatem.
  5. Jeśli nie wysłaliśmy formularza to go wyświetlamy.
  function admin_edytuj($id) {
        $id = (int)$id;
        if(isset($_POST['tytul']) && isset($_POST['tresc'])) {
            $tytul = $this->czysc($_POST['tytul']);
            $tresc = $this->czysc($_POST['tresc']);
            $result = mysql_query("UPDATE strony SET tytul = '$tytul', tresc = '$tresc' WHERE id = '$id'");
            if($result) {
                echo '<p>Zaktualizowano poprawnie! <a href="index.php?page='.$id.'">Przejdź do strony</a></p>';
            }
        } else {
            $row = $this->strona($id);
            echo '<form action="" method="POST">
                    <label>Tytuł:</label><br>
                    <input type="text" name="tytul" style="width:500px" value="'.$row['tytul'].'"><br>
                    <label>Treść:</label><br>
                    <textarea style="width:500px" rows="10" name="tresc" id="tresc">'.$row['tresc'].'</textarea>
                    <input type="submit" value="Wyślij">
                </form>';
        }
    }

Podobna funkcja do tej wyżej na edycję strony. Wszystko jest praktycznie tak samo tylko że wykonujemy zapytanie UPDATE a nie INSERT. Jeśli formularz nie został jeszcze wysłany to go wyświetlamy z wypełnionymi polami. Korzystamy tutaj też z funkcji strona()

  function admin_usun($id) {
        $result = mysql_query("DELETE FROM strony WHERE id = '$id'");
        if($result) {
            echo '<p>Pomyślnie usunięto stronę! <a href="admin.php">Wróć do strony głównej</a>.</p>';
        }
    }

Bardzo prosta funkcja na usuwanie strony. Raczej nic tu trudnego nie ma i obejdzie się bez komentarza ;)

No i to by było na tyle. Jeszcze tylko funkcje pomocnicze czysc() i stripslashes_deep()

  function czysc($tresc) {
        $tresc = mysql_real_escape_string($tresc);
        return $tresc;
    }
 
    function stripslashes_deep($value) {
        $value = is_array($value) ?
                array_map(Array($this, 'stripslashes_deep'), $value) :
                stripslashes($value);
        return $value;
    }

Funkcja czysc() to tak jakby alias dla funkcji mysqlrealescape_string(). Istnieje ona ponieważ ma krótszą nazwę oraz zawsze możemy coś jeszcze dodać zmieniając kod tylko w jednym miejscu.

Co do stripslashesdeep() to jeśli $value jest tablicą to używamy na niej funkcji arraymap (dla każdej wartości w tablicy zostanie wywołana funkcja w pierwszym parametrze funkcji). Jeśli $value nie jest tablicą to używamy zwykłego stripslashes. Funkcja została zaczerpnięta z manuala pod funkcją stripslashes.

Ciekawostka: Jeśli w funkcji w której podajemy nazwę funkcji (preg_replace, array_map itd) chcemy użyć funkcji należącej w jakiejś klasie używamy tablicy. Pierwsza wartość to odwołanie (np. $this) a druga to nazwa funkcji. Przykład w powyższej funkcji stripslashes_deep.

Dobra, klasę już mamy, teraz trzeba ją wywołać. Więc stworzymy sobie plik index.php a w nim:

<html>
<head>
<title>Moja strona</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<?php
 
include "strony.class.php";
 
$strony = new Strony;
if(isset($_GET['page'])) $strony->pokaz($_GET['page']);
else $strony->lista();
 
?>
</body>
</html>

Jak widać standardowy szablon HTML, kodowanie UTF-8. Używając PHP załączamy plik z klasą. Tworzymy nowy obiekt i jeśli jest używana zmienna $GET['page'] to wywołujemy funkcję pokaz() ze zmienną $GET w parametrze. W przeciwnym wypadku wyświetlamy listę stron (można tam na przykład znając ID kontretnej strony wstawić $strony->pokaz(123); gdzie 123 to ID strony głównej).

Teraz panel administratora - plik admin.php:

<?php session_start(); ?>
<html>
<head>
<title>Panel administratora</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="http://js.nicedit.com/nicEdit-latest.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(function(){new nicEditor({fullPanel : true}).panelInstance('tresc'); });</script>
</head>
<body>
<?php
 
include "strony.class.php";
 
echo '<a href="admin.php"><h3>Panel administratora</h3></a>';
$strony = new Strony;
$strony->admin();
 
?>
</body>
</html>

Na początek startujemy sesje aby było możliwe logowanie. Jak widać jest też standardowy szablon HTML. Ale tutaj jest mały dodatek - edytor tekstowy WYSIWYG Nicedit. Nie musimy nic pobierać ponieważ edytor jest na zewnętrzym serwerze ;)

W środku strony ładujemy plik z klasą, wyświetlamy napis "Panel administratora", tworzymy nowy obiekt klasy i wywołujemy funkcję admin().

No i to by było na tyle ;) Mamy już własny system podstron w PHP!