Skrypt galerii zdjęć z panelem administracyjnym (PHP, Bootstrap, MySQL)

PHP + MySQL

Bartosz Stefanicki, 22.04.2024

Skrypt galerii zdjęć z panelem administracyjnym (PHP, Bootstrap, MySQL)

Posiadasz wiele fotografii, które chcesz komuś pokazać? Stworzymy skrypt galerii zdjęć, którą będziemy mogli zarządzać przez panel administracyjny.

Wcześniej omówiliśmy "Prosty skrypt galerii zdjęć z efektem Highslide" i drugą, bardziej rozbudowaną wersję "Prosty skrypt galerii zdjęć z efektem Highslide – wersja 2". Przyjrzyjmy się, co tym razem będzie obejmował skrypt galerii zdjęć. Jest to wersja 3.

Opis galerii

  • Skrypt galerii zdjęć - prezentacja zdjęć z opisami, umieszczonych w różnych kategoriach,
  • Panel administracyjny - zarządzanie zdjęciami (usuwanie, dodawanie zdjęć, dodawanie opisów do zdjęć, wybór kategorii dla zdjęć) i kategoriami (usuwanie, dodawanie),
  • Bootstrap - zastosowałem responsywność (galeria i panel są dostosowane do urządzeń mobilnych, smartfonów itp.) oraz kilka gotowych elementów CSS,
  • Panel administracyjny na sesjach (login: admin, hasło: admin),
  • Baza danych MySQL,

Struktura plików

  • / - pliki skryptu galerii zdjęć, pliki panelu administracyjnego,
  • /img - zdjęcia z galerii,
  • /dist - pliki Bootstrapa,

1. Plik galerii zdjęć (galeria.php)

Poniżej pierwszy plik "galeria.php". Wyświetla on dostępne kategorie, następnie zdjęcia. Na początku pokażę, jak będzie wyglądał nagłówek:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Galeria zdjęć wykorzystująca PHP, HTML 5, CSS 3, Bootstrap">
    <meta name="author" content="itporady.pl">
    <title>GZ galeria zdjęć</title>

    <!-- Bootstrap core CSS -->
    <link href="dist/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- Custom styles for this template -->
    <link href="style.css" rel="stylesheet">
</head>
<body>

<div class="container">
<!-- Static navbar -->

<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">

<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
	<span class="sr-only">Toggle navigation</span>
	<span class="icon-bar"></span>
	<span class="icon-bar"></span>
	<span class="icon-bar"></span>
</button>

<a class="navbar-brand" href="kokpit.php">GZ galeria zdjęć</a>
</div>

<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
	<li><a href="kokpit.php">Kokpit</a></li>    
    <li><a href="galeria.php">Zobacz galerię</a></li>
    </ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</nav>

Zdefiniowaliśmy tytuł strony, lokalizację plików JavaScript oraz menu. Teraz część pierwsza kodu PHP. Jeśli nie wybrano kategorii, to wyświetlana jest ich lista:

<?php
//jeśli nie wybrano kategorii, czyli krok 1/2 to...
$zmienna = 'zmienna';
$kategoria = $_GET['kategoria'];
if( !$kategoria ){
?>

<div class="page-header">
	<h1>Kategorie zdjęć</h1>
</div>

<div class="row">
<div class="col-md-12">

<table class="table">
<thead>
<tr>
	<th>ID</th>
	<th>Nazwa kategorii</th>
	<th>Opcje</th>
</tr>
</thead>
<tbody>
<?php
require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("SELECT * FROM kategorie;");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<tr>';
	echo '<td>'.$tabela['id'].'</td><td>'.$tabela['nazwa'].'</td>'; 
	echo '<td><a href="galeria.php?kategoria='.$tabela['id'].'" type="button" class="btn btn-xs btn-primary">Przejdź do kategorii</a></td>';
	echo '</tr>';
}

mysql_close($connect);
?>
</tbody>
</table>

</div>
</div>

Jeśli użytkownik wybrał kategorię, to pokazujemy zdjęcia z wybranej kategorii:

<?php
//jeśli wybrano kategorię, czyli krok 2/2 to...
}else{

//pobieranie danych do połączenia
require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("SELECT nazwa FROM kategorie WHERE id = '$kategoria';");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<div class="page-header"><h1>Zdjęcia w kategorii: "'.$tabela['nazwa'].'" </h1><a href="galeria.php" class="btn btn-xs btn-primary">Przejdź do innej kategorii</a></div><div class="row"><div class="col-md-12">';
}

//definiuje zapytanie
$sql = mysql_query("SELECT * FROM zdjecia WHERE id_kategorii = '$kategoria';");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<div class="col-xs-6 col-md-3"><a href="img/'.$tabela['id'].'.jpg" class="thumbnail"><img src="img/'.$tabela['id'].'.jpg" alt="">&nbsp;'.$tabela['nazwa'].'</a></div>';
}

//zamknięcie połączenia
mysql_close($connect);
?>
</tbody>
</table>

</div>
</div>

<?php } ?>

</div> <!-- /container -->

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="dist/js/bootstrap.min.js"></script>
</body>
</html>

Na końcu jeszcze załączyliśmy bibliotekę jQuery. Przejdźmy do panelu administracyjnego.

2. Panel administracyjny (index.php, kokpit.php)

Na początku instrukcje dla bazy danych. Posłużymy się tylko bazą MySQL (PostgreSQL udostępniam jako opcję dodatkową do pobrania).

2.1. Instrukcje MySQL (instrukcje.txt)

Te polecenia utworzą nam w bazie danych odpowiednie tabele. Należy przejść na przykład do phpMyAdmin, tam wybrać opcję "Import" i wkleić poniższy kod.

CREATE TABLE kategorie (
    id int NOT NULL AUTO_INCREMENT,
    nazwa VARCHAR (20) not null,
    PRIMARY KEY (id)
);


CREATE TABLE zdjecia (
    id int NOT NULL AUTO_INCREMENT,
    id_kategorii int not null,
    PRIMARY KEY (id),
    FOREIGN KEY (id_kategorii)
    REFERENCES kategorie(id)
);

CREATE TABLE uzytkownicy (
    id int NOT NULL AUTO_INCREMENT,
    login VARCHAR (128) not null,
    haslo VARCHAR (128) not null,
    PRIMARY KEY (id)
);

INSERT INTO uzytkownicy (login, haslo) VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3');

Tworzymy 3 tabele: kategorie, zdjęcia, użytkownicy. Umieszczamy w tabeli "użytkownicy" nowy rekord o ID 1, nazwa to admin, hasło to admin (zakodowane metodą md5).

2.2. Formularz do logowania (index.php)

Jeżeli będziemy chcieli się zalogować do panelu administracyjnego, to pierwszym krokiem będzie zalogowanie się. Także musimy zdefiniować formularz z polem "login" i "hasło", potem po wysłaniu danych, połączyć się z bazą danych i sprawdzić czy są dane tu i tu zgodne ze sobą.

<?php
//wlaczenie bufora wyjsciowego
ob_start();
//rozpoczyna sesje
session_start();
//pobiera dane do bazy danych
require 'polaczenie.php';
?>

<!-- ...Tutaj jest head, menu... -->

<div class="page-header">
	<h1>Panel logowania</h1>
</div>

Inicjujemy sesję i pobieramy dane do bazy danych z pliku polaczenie.php.

<div class="row">
<div class="col-md-12">
<?php
//funkcja do wylogowania
switch($_GET['p']){
	case 'wyloguj':
		session_destroy();
		$_SESSION = array ();
		echo '<div class="alert alert-success">Zostałeś wylogowany.</div>';
	break;
}

//SKRYPT LOGOWANIA
//dane z formularza
$login = htmlspecialchars(mysql_real_escape_string($_POST['login']));
$pass = mysql_real_escape_string($_POST['haslo']);

if( $_POST['send'] == 1 ){
	//sprawdza, czy wszystkie pola sa wypelnione
	if( !$login or empty($login) ){
		die ('<div class="alert alert-danger">Wypełnij pole z nazwą użytkownika. <a href="index.php" class="alert-link">Wróć do formularza</a>.</div>');
    }

    if( !$pass or empty($pass) ){
        die ('<div class="alert alert-danger">Wypełnij pole z hasłem. <a href="index.php" class="alert-link">Wróć do formularza</a>.</div>');
    }

	//koduje haslo
    $pass = md5($pass);
    
    //sprawdza, czy uzytkownik istnieje w bazie danych
    $userExists = mysql_fetch_array(mysql_query("SELECT COUNT(*) FROM uzytkownicy WHERE login = '$login' AND haslo = '$pass'"));

	//jesli uzytkownik nie istnieje, to...
    if ($userExists[0] == 0) {
        // Użytkownik nie istnieje w bazie
        echo '<div class="alert alert-danger">Podany użytkownik nie istnieje. <a href="index.php" class="alert-link">Wróć do formularza</a>.</div>';
    }

	//jesli uzytkownik istnieje, to...
    else {
    	//przypisz pobrane dane do sesji
    	$_SESSION['login'] = $login;
        $_SESSION['pass'] = $pass;
		//przekieruj uzytkownika do kokpitu
        header ('Location: kokpit.php');
    }
}

//wyswietla formularz do logowania
else {
?>

<form method="post" action="index.php" class="form-horizontal">
<div class="form-group">
	<label for="login" class="col-sm-2 control-label">Nazwa użytkownika</label>
    <div class="col-sm-4">
		<input type="text" class="form-control" name="login" id="login">
    </div>
</div>
<div class="form-group">
	<label for="haslo" class="col-sm-2 control-label">Hasło</label>
    <div class="col-sm-4">
		<input type="password" class="form-control" name="haslo" id="haslo">
    </div>
</div>
<div class="form-group">
    <div class="col-sm-offset-2 col-sm-4">
      <input type="submit" value="Zaloguj się" class="btn btn-default">
    </div>
  </div>
<input type="hidden" name="send" value="1" />
</form>

<?php
}
?>

</div>
</div>

</div> <!-- /container -->

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="dist/js/bootstrap.min.js"></script>
</body>
</html><?php ob_end_flush(); ?>

Jeśli dane z formularza zgadzają się z danymi w bazie danych, to użytkownik zostaje zalogowany i przenosimy go do kokpitu administratora. Jeśli dane są błędne, to wyświetla się komunikat z błędem. Pora na plik z danymi do połączenia z bazą danych MySQL, polaczenie.php:

<?php
//definiuje połączenie, tutaj trzeba wpisać dane do połączenia
$connect = @mysql_connect('localhost', 'NAZWA_UZYTKOWNIKA', 'HASLO_UZYTKOWNIKA') or die('<div class="alert alert-danger" role="alert">Błąd przy połączeniu.</div>');

$baza = mysql_select_db("NAZWA_BAZY_DANYCH", $connect) or die('<div class="alert alert-danger" role="alert">Błąd przy wybraniu bazy danych.</div>');
?>

2.3. Dodaj kategorię (dodajkategorie.php)

<?php
//sprawdzenie, czy uzytkownik jest zalogowany
if (empty($_SESSION['login']) || empty($_SESSION['pass'])) {
	header('Location: index.php');
}
?><div class="page-header">
	<h1>Dodaj kategorię</h1>
</div>

<?php
//sprawdzenie, czy jest wysłany formularz
$nazwa = $_POST['nazwa'];
if( $nazwa ){

//definiuje zapytanie
$sql = mysql_query("INSERT INTO kategorie SET nazwa = '$nazwa';");

//wyświetlenie komunikatu o powodzeniu, lub niepowodzeniu
if( $sql ){
	echo '<div class="alert alert-success" role="alert">Kategoria "'.$nazwa.'" została pomyślnie dodana.</div>'; 
} else {
    echo '<div class="alert alert-danger" role="alert">Błąd przy dodawaniu kategorii "'.$nazwa.'".</div>';
}

//zamknięcie połączenia
mysql_close($connect);

}
?>

<div class="row">
<div class="col-md-5">

<form action="kokpit.php?p=dodajkategorie" method="post">
<div class="form-group">
	<label for="nazwa">Podaj nazwę nowej kategorii</label>
    <input type="text" id="nazwa" name="nazwa" class="form-control" required>
</div>

  <button type="submit" class="btn btn-primary">Dodaj kategorię</button>
</form>

</div>
</div>

2.4. Dodaj zdjęcie (dodajzdjecia.php)

Formularz z możliwością zaznaczenia kilku zdjęć i wysłania ich na serwer. Skrypt pobiera ostatnio przyznany identyfikator zdjęcia, zwiększa go o 1. Uzyskany ID to nowa nazwa zdjęcia na serwerze i identyfikator zdjęcia w bazie danych. Oprócz tego można wybrać kategorię z listy rozwijanej.

<?php
//sprawdzenie, czy uzytkownik jest zalogowany
if (empty($_SESSION['login']) || empty($_SESSION['pass'])) {
	header('Location: index.php');
}
?><div class="page-header">
	<h1>Dodaj zdjęcia</h1>
</div>


<?php 
//sprawdzenie, czy jest wysłany formularz
if( $_POST ){

//deklarowanie zmiennych
$kategoria = $_POST['kategoria'];

//DODANIE PLIKU DO BAZY DANYCH
//pobieranie danych do połączenia
require( 'polaczenie.php' );

//definiuje zapytanie - pobiera ostatni ID z tabeli zdjęcia
$sql = mysql_query("SELECT MAX(id) FROM zdjecia;");
while( $row = mysql_fetch_array($sql) ){
	//przypisuje ostatni ID zmiennej $najwiekszeID i powiększa o 1
	$najwiekszeID = $row[0]+1;
}
	
//WYSYŁANIE PLIKU NA SERWER
for( $i=0; $i<count($_FILES['plik']['size']); $i++ ){ 

if( strstr($_FILES['plik']['type'][$i], 'image')!==false ){ 

	//zmienia nazwę pliku, by zgadzały się z ID w bazie danych
	$file = 'img/'.$najwiekszeID.'.jpg'; 
	//wysyła plik na serwer
	move_uploaded_file($_FILES['plik']['tmp_name'][$i], $file); 

	//dodaje wpis do bazy danych
	$sql = mysql_query("INSERT INTO zdjecia SET id_kategorii = '$kategoria';");
	//wyświetlenie komunikatu o powodzeniu, lub niepowodzeniu
	if( $sql ){
		echo '<div class="alert alert-success" role="alert">Zdjęcia zostały zapisane w bazie danych.</div>'; 
	} else {
		echo '<div class="alert alert-danger" role="alert">Błąd przy zapisie zdjęć do bazy danych.</div>';
}

	//wyświetla komunikat o powodzeniu
	echo '<div class="alert alert-success" role="alert">Zdjęcia zostały zapisane na serwerze.</div>';
	//zwiększa ID dla kolejnych zdjęć w pętli
	$najwiekszeID++;
} 
}

//zamknięcie połączenia
mysql_close($connect);

}
?>

<div class="row">
<div class="col-md-5">

<form action="kokpit.php?p=dodajzdjecia" method="post" enctype="multipart/form-data">
<div class="form-group">
	<label for="kategoria">Wybierz kategorię</label>
    <select id="kategoria" name="kategoria" class="form-control">
<?php
//pobieranie danych do połączenia
require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("SELECT id, nazwa FROM kategorie;");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<option value="'.$tabela['id'].'">'.$tabela['nazwa'].'</option>'; 
}

//zamknięcie połączenia
mysql_close($connect);
?>
	</select>
</div>

<div class="form-group">
	<label for="pliki">Wybierz zdjęcia</label>
    <input type="file" id="pliki" multiple="multiple" name="plik[]">
</div>

  <button type="submit" name="wyslij" class="btn btn-primary">Dodaj zdjęcia</button>
</form>

</div>
</div>

2.5. Edytowanie zdjęć (edytujzdjecia.php)

W tym miejscu będziemy mogli wybrać kategorię. Następnie z wybranej kategorii usunąć zdjęcie lub dodać do niego opis.

<?php
//sprawdzenie, czy uzytkownik jest zalogowany
if (empty($_SESSION['login']) || empty($_SESSION['pass'])) {
	header('Location: index.php');
}
?><div class="page-header">
	<h1>Dodaj zdjęcia</h1>
</div>


<?php 
//sprawdzenie, czy jest wysłany formularz
if( $_POST ){

//deklarowanie zmiennych
$kategoria = $_POST['kategoria'];

//DODANIE PLIKU DO BAZY DANYCH
//pobieranie danych do połączenia
require( 'polaczenie.php' );

//definiuje zapytanie - pobiera ostatni ID z tabeli zdjęcia
$sql = mysql_query("SELECT MAX(id) FROM zdjecia;");
while( $row = mysql_fetch_array($sql) ){
	//przypisuje ostatni ID zmiennej $najwiekszeID i powiększa o 1
	$najwiekszeID = $row[0]+1;
}
	
//WYSYŁANIE PLIKU NA SERWER
for( $i=0; $i<count($_FILES['plik']['size']); $i++ ){ 

if( strstr($_FILES['plik']['type'][$i], 'image')!==false ){ 

	//zmienia nazwę pliku, by zgadzały się z ID w bazie danych
	$file = 'img/'.$najwiekszeID.'.jpg'; 
	//wysyła plik na serwer
	move_uploaded_file($_FILES['plik']['tmp_name'][$i], $file); 

	//dodaje wpis do bazy danych
	$sql = mysql_query("INSERT INTO zdjecia SET id_kategorii = '$kategoria';");
	//wyświetlenie komunikatu o powodzeniu, lub niepowodzeniu
	if( $sql ){
		echo '<div class="alert alert-success" role="alert">Zdjęcia zostały zapisane w bazie danych.</div>'; 
	} else {
		echo '<div class="alert alert-danger" role="alert">Błąd przy zapisie zdjęć do bazy danych.</div>';
}

	//wyświetla komunikat o powodzeniu
	echo '<div class="alert alert-success" role="alert">Zdjęcia zostały zapisane na serwerze.</div>';
	//zwiększa ID dla kolejnych zdjęć w pętli
	$najwiekszeID++;
} 
}

//zamknięcie połączenia
mysql_close($connect);

}
?>


<div class="row">
<div class="col-md-5">

<form action="kokpit.php?p=dodajzdjecia" method="post" enctype="multipart/form-data">
<div class="form-group">
	<label for="kategoria">Wybierz kategorię</label>
    <select id="kategoria" name="kategoria" class="form-control">
<?php
//pobieranie danych do połączenia
require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("SELECT id, nazwa FROM kategorie;");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<option value="'.$tabela['id'].'">'.$tabela['nazwa'].'</option>'; 
}

//zamknięcie połączenia
mysql_close($connect);
?>
	</select>
</div>

<div class="form-group">
	<label for="pliki">Wybierz zdjęcia</label>
    <input type="file" id="pliki" multiple="multiple" name="plik[]">
</div>

  <button type="submit" name="wyslij" class="btn btn-primary">Dodaj zdjęcia</button>
</form>

</div>
</div>

2.6. Usuń kategorię (usunkategorie.php)

Tutaj wyświetlą się nam wszystkie kategorie. W tabelce wyświetli się opcja usunięcia wybranej.

<?php
//sprawdzenie, czy uzytkownik jest zalogowany
if (empty($_SESSION['login']) || empty($_SESSION['pass'])) {
	header('Location: index.php');
}
?><div class="page-header">
	<h1>Usuń kategorię</h1>
</div>

<?php
//sprawdzenie, czy jest zmienna
$nazwa = $_GET['nazwa'];
if( $nazwa ){

require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("DELETE FROM kategorie WHERE id = '$nazwa';");

if( $sql ){
	echo '<div class="alert alert-success" role="alert">Kategoria "'.$nazwa.'" została pomyślnie usunięta.</div>'; 
} else {
    echo '<div class="alert alert-danger" role="alert">Błąd przy usuwaniu kategorii o identyfikatorze "'.$nazwa.'".</div>';
}

mysql_close($connect);

}
?>

<div class="row">
<div class="col-md-12">

<table class="table">
<thead>
<tr>
	<th>ID</th>
	<th>Nazwa kategorii</th>
	<th>Opcje</th>
</tr>
</thead>
<tbody>
<?php
require( 'polaczenie.php' );

//definiuje zapytanie
$sql = mysql_query("SELECT * FROM kategorie;");

//wyświetla wynik
while( $tabela = mysql_fetch_array($sql) ){ 
	echo '<tr>';
	echo '<td>'.$tabela['id'].'</td><td>'.$tabela['nazwa'].'</td>'; 
	echo '<td><a href="kokpit.php?p=usunkategorie&nazwa='.$tabela['id'].'" type="button" class="btn btn-xs btn-danger">Usuń kategorię</a></td>';
	echo '</tr>';
}

mysql_close($connect);
?>
</tbody>
</table>

</div>
</div>

2.7. Kokpit (kokpit.php)

Tutaj po prawidłowym zalogowaniu użytkownika wyświetla się komunikat powitalny, a także linki umożliwiające edycję zdjęć/kategorii.

<?php
	session_start();
	require_once('polaczenie.php');

//sprawdzenie, czy uzytkownik jest zalogowany
if (empty($_SESSION['login']) || empty($_SESSION['pass'])) {
	header('Location: index.php');
}
?><!-- ...Tutaj jest head, menu... -->

<?php
switch($_GET['p']){
	case 'dodajzdjecia':
		include('dodajzdjecia.php');
	break;
	case 'dodajkategorie':
		include('dodajkategorie.php');
	break;
	case 'edytujzdjecia':
		include('edytujzdjecia.php');
	break;
	case 'usunkategorie':
		include('usunkategorie.php');
	break;
	default:
		echo '<div class="jumbotron"><h1>Witaj!</h1><p>Znajdujesz się w panelu administratora. Możesz tutaj dodawać/usuwać zdjęcia i kategorie. Wybierz pozycję z menu w prawym górnym rogu.</p></div>'; 
}
?>

</div> <!-- /container -->

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="dist/js/bootstrap.min.js"></script>
</body>
</html>

3. Bootstrap

Plików z Bootstrapa nie będę załączał. Jest to framework, zawiera gotowe rozwiązania odnośnie responsywności i elementów CSS.

4. Arkusz stylów CSS (style.css)

W arkuszu nie ma dużo kodu, zaledwie kilka linijek. Resztę stylów załatwia Bootstrap.

body {
  padding-top: 20px;
  padding-bottom: 20px;
}

.navbar {
  margin-bottom: 20px;
}

a.thumbnail img{
	height:200px;
}

Podsumowanie

Utworzyliśmy responsywną galerię zdjęć z podziałem na kategorie. Jest oparta na bazie danych MySQL. Zawiera panel administracyjny (tak zwany "Kokpit") umożliwiający dodawanie / usuwanie zdjęć i kategorii, a także na dodawanie / zmianę opisu zdjęć. Panel administracyjny jest oparty na sesjach.

Pobierz

Szukasz hostingu?

Jest dużo firm oferujących hosting, ale którą wybrać? Przedstawiamy zestawienie najciekawszych propozycji i ranking hostingów (Październik 2024).

66 komentarzy

Ostatnie komentarze

Statystyki

  • 199

    Liczba porad
  • 1 996

    Liczba komentarzy
  • 5

    Narzędzi online

© 2005-2024 itporady.pl. Wszystkie prawa zastrzeżone.

Strona korzysta z plików cookies w celu realizacji usług i zgodnie z Polityką prywatności. Możesz określić warunki przechowywania lub dostępu do plików cookies w Twojej przeglądarce.