Webboard

Pełna wersja: PHP + mySQLi - mini cms
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Stron: 1 2
Hej!
Złapałem trochę weny twórczej w skrzydła. Próbuję podłapać trochę praktycznego kodu php/mysql na potrzeby własne. 
Docelowo chce sobie stworzyć coś na zasadzie mini cms'a. W sumie nano-cms'a lub jeszcze mniejsze. Idea jest taka, że chcę stworzyć sobie coś, z czego sam będę korzystał, a przy okazji zrozumieć mniej więcej jak to działa. 

Na podstawie paru poradników, stworzyłem sobie logowanie do mojej strony. W tym celu powstały już pliki:
  • index.php - strona główna
  • login.php - strona z panelem logowania 
  • s_login.php - skrypt otwierający połączenie z bazą i sprawdzający czy podane dane zgadzają się z tymi z tabeli użytkownicy. Jeśli wszystko poszło pomyślnie, tworzy się sesja, która jest wykorzystywana w podstronach typu index - do sprawdzania czy jesteśmy zalogowani, lub do wyświetlania nazwy zalogowanego konta, która to została wrzucona w sesję, aby móc jej użyć w innym pliku - index.
  • config.php - zawierający dane logowania do bazy danych
  • logout.php  - kończący sesje, przenoszący do strony głównej, tudzież panelu logowania
Już w tym momencie, gdy w zasadzie jedyną funkcjonalnością jest zalogowanie się mam 5 plików. Do nawigacji pomiędzy plikami w zależności od stanu zalogowania używam header('Location: index.php');

I teraz pytania. 
  1.  Jak najlepiej zoptymalizować te pliki. Logowanie w zasadzie sprowadza się do otworzenia połączenia z bazą i wysłania zapytania. Każdy kolejny skrypt też będzie musiał nawiązać połączenie z bazą i wysłać swoje instrukcje. To tworzy nie tylko wiele plików, ale w dodatku - powtórzenia. Wstęp zawsze będzie ten sam - połączenie z bazą. Jest sens to wrzucić w osobny plik i każdorazowo robić include? W zasadzie to zaledwie parę linijek.
  2. Stworzyłem sobie prosty 'panel' do dodawania nowych użytkowników. Muszę go trochę poprawić, przede wszystkim zabezpieczyć, ale działa. Teraz próbuje dodać możliwość wyświetlania tabeli userów, wszystkich rekordów. Docelowo będzie to w zakładce użytkownicy, ale na tym etapie jest to po prostu button na stronie głównej, który metodą post odwołuje się do skryptu wykonującego zapytanie po uprzednim połączeniu z bazą. W chwili obecnej fragment ten wygląda tak:
    <-- Ze względu na problemy z formatowaniem kodu php, kod zamieszczam poniżej listy pytań -->
  3. Przycisk po kliknięciu przenosi na podstronę s_showusers.php i wywala kolejno dane każdego użytkownika. Pytanie: Chcę to ładnie ubrać w tabelkę, która będzie się wyświetlała w określonym miejscu, np. <div id="tutaj"></div> w osobnym pliku, np. index.php albo users.php. Jak, jakiej funkcji/metody użyć by wynik skryptu przenieść w wybrane miejsce. 
  4. Póki co każda akcja jest wykonywana przyciskiem, który metodą post wywołuje odpowiedni skrypt. W jaki, lepszy sposób uzyskać podobny efekt. Przede wszystkim, chciałbym uzyskać możliwość pisania większości bliźniaczych funkcji/instrukcji w jednym pliku... na początku otwierałbym połączenie z bazą, a następnie w zależności od wybranej akcji wykonywałaby się jedna z wielu funkcji.
Kod z pytania 2. 
Kod PHP:
$sql $db_connect->query("SELECT * FROM uzytkownicy ORDER BY id ASC"); 
while ($row mysqli_fetch_row($sql)) 

echo 
$row[1] ."<br />"
echo 
$row[2] ."<br />"
echo 
$row[3] ."<br />"

ad. 1 - Żeby wiedzieć co można optymalizować trzeba widzieć kod. Metoda includowania jednego pliku z danymi do bazy jest o tyle wygoda że jeśli zmienią się dane do niej to nie trzeba grzebać w 20 plikach.
ad. 2 - nie wiem o co pytasz
ad. 3 - o ile dobrze rozumiem, najlepiej w pliku pobierającym i tworzącym liste zrobić to w funkcji, później includujesz plik i wywołujesz funkcje tam gdzie potrzebujesz.
ad. 4 - ja bym to zrobił tak. Plik include/funkcje.php pierwsza funkcja polaczenie do bazy, następna funkcja llista userów i w niej można już wywołać pierwszą. następna menu_strony() - zwróci menu żeby nie kopiować po kilku plikach itd itd it, i żyli długo i ...

Kod PHP:
echo '<div id="tutaj">
<table>
<tr>
    <td>lista</td>    
</tr>'
;
$sql $db_connect->query("SELECT * FROM uzytkownicy ORDER BY id ASC"); 
while (
$row mysqli_fetch_row($sql)) 

echo 
'<tr>
    <td>'
.$row[1].'</td>
</tr>'


echo 
'</table></div>'

najważniejsze jest bezpieczeństwo bazy, pamiętaj.

Tak naprawdę (jak już gdzieś kiedyś usłyszałem) programistę ogranicza tylko wyobrażania, bo umiejętności można nabyć, i to tylko od Ciebie zależy jak co będzie wyglądało w Twoim skrypcie.
(17.03.2016, 18:09)Supryk napisał(a): [ -> ]ad. 1 - Żeby wiedzieć co można optymalizować trzeba widzieć kod. Metoda includowania jednego pliku z danymi do bazy jest o tyle wygoda że jeśli zmienią się dane do niej to nie trzeba grzebać w 20 plikach.

W zasadzie bardziej niż o optymalizacje kodu, ilości zapytań etc. chodziło mi o sposób na ograniczenie plików. Poniekąd wiąże się to z punktem czwartym.

(17.03.2016, 18:09)Supryk napisał(a): [ -> ]ad. 2 - nie wiem o co pytasz

Mniej więcej o to, co umieściłeś w tagach php :D O ile samo stworzenie tabelki na podstronie wykonującej skrypt nie jest problemem, nie wiem jak i jakiej konkretnie funkcji użyć by przenieść wygenerowaną tabelę do osobnego pliku, szablonu strony.
Teraz patrzę, że podczas pisania posta zrobiłem za wiele punktów. Punkt trzeci jest kontynuacją punktu drugiego, wybacz zamieszanie.

Teraz myślę, że widzę jeden z brakujących elementów. Myślałem wcześniej o zbiorczym pliku na funkcje, ale nie przemyślałem ich wywoływania. Dziś się z tym pobawię i zdam relację z napotkanych problemów.


//edit.
no way.
Dałem include plik z funkcjami, problem w tym - jak je wywołać.
Przykładowo skrypt dodający usera do bazy wykonuje się formularzem przy pomocy action. Nie mogę w action dać nazwy funkcji, musi być odniesienie do pliku .php ze skryptem.

I w tym miejscu zataczam koło. Jeśli wywołam tylko ten jeden skrypt - s_addusers.php to tabela z userami wygeneruje się w tamtym pliku ze skryptem. Mogę ją umieścić w jakieś funkcji i wywołać ją normalnie w pożądanym miejscu na stronie głównej... nie, nie mogę. Formularz dodaje do bazy metodą POST, więc musi się wysłać. Proces idzie tak -> otwierasz stronę główną, załącza się plik z funkcjami, wypełniasz formularz -> skrypt startuje: formularz wysyła żądanie do serwera, dodaje się użytkownik do bazy, tworzy się funkcja wyświetlająca tabele, przekierowuje z powrotem na stronę główną gdzie powinno wyświetlić tabelę, ale tego nie zrobi.
Musi być lepszy, poprawniejszy na to sposób.
Przede wszystkim, skrypty php o ile rozumiem poprawnie - muszą się wysłać, więc załączony plik z funkcjami nic nie da.
a proszę Cię bardzo
może chociaż zobrazuje Ci jak to wedle mnie powiano być

ja nie twierdze ze w pliku z funkcjami masz trzymac wszystko

plik
logowanie.php bez parametrów wyświetla formularz
logowanie.php?action=zaloguj i to mozna bawić się funckajmi
logowanie.php?action=blad jakas strona bledu

Kod PHP:
function sprawdz_czy_user_istnieje($login)
{
// sprawdzamy w bazie czy istnieje
if($wynik_z_bazy)
{
return 
true;
}
else
{
header('Location: logowanie.php?action=blad');
}

Powiem szczerze, że głupio mi niektóre pytania zadawać bo widać jakie braki w wiedzy mam. Sęk w tym, że ja jestem takim typem co uczyć się może, ale na konkretnym przykładzie i zastosowaniu. Tak więc, będę pytał. Dzięki za zaangażowanie! :)

Twoja paczka mi sporo objaśniła, obrobiłem swój kod w tym i działa.
Dobrą zagwostkę miałem z linkami o których wspominałeś, aby wywoływać akcje z linku. Ogólnie - nawigacja między funkcjami i parametrami jak widać jest jednym z większych braków. Nie miałem okazji przetestować pomysłów jeszcze - wieczór, obecnie poza domem. Anyway, czy dobrze rozumuje.

Cytat:logowanie.php?action=blad jakas strona bledu
Pomysł podpatrzyłem w plikach mybb, ale wykonanie już nie koniecznie mi wypaliło.
Do formularza dodałem input hidden z danym value i name="action".
Teraz, w login.php, logowanie umieściłem w funkcji. Funkcję tą chciałbym wywołać w momencie gdy link przybierze wartość login.php?action=login.
Jak odnieść się do tej konkretnej funkcji za pomocą ukrytego inputa, a może jeszcze w inny sposób.
Coś czuje, że to będzie swego rodzaju kamień milowy, zwłaszcza, że później coraz więcej informacji będę chciał próbować przekazywać w urlu - choćby kasowanie użytkowników delete.php?id=$id.
Samo logowanie trzymaj w pliku - wykorzystuj w kodzie fukcje powtarzalne, funkcja - wykorzystuj ją tam gdzie powtarzasz pewne działania, na przykładzie czy użytkownik istnieje

wykorzystasz
podczas logowania
podczas rejestracji - by nie dublować loginów emaili

Tak możesz w formularzy dać ukryty input o nazwie action

pozniej w pliku php sprawdzasz

Kod PHP:
if($_POST['action'] == "akcja")
{

}
esleif($_POST['action'] == "akcja2")
{

}
esleif(!$_POST['action'])
{



Ja sam robię błąd że nie umieszczam pewnych rzeczy w funkcjach, muszy wyrobić u siebie ten nawyk
Wtrącę się a co.
Jak już znasz się trochę na PHP, to może spróbuj obiektowego wtedy wszystko wydaje się prostsze moim zdaniem.
Wtedy będzie optymalnie bo cała klasa będzię tylko w jednym pliku ;)

przykład:
Kod PHP:
<?php

class mojCMS {
    protected 
$cmsmysql = [];
    protected 
$cmsmysql['host'] = "localhost";
    protected 
$cmsmysql['name'] = "root";
    protected 
$cmsmysql['password'] = "password";
    protected 
$cmsmysql['table'] = "database";
    public 
$db;
    private 
$error 0;

    function 
__construct() {
        
$this->db = new mysqli_connect($this->cmsmysql['host'], $this->cmsmysql['name'], $this->cmsmysql['password'], $this->cmsmysql['table']);
        if(
$this->db->connect_errno) {
            
$this->error 1;
        } else {
            
session_start();
        }
    }
    function 
loguj($login$haslo) {
        if(
$error == 0) {
            
$login $this->db->real_escape_string($login);
            
$haslo md5($haslo);
            
$query $this->db->query("SELECT * FROM `tabelkazuserami` wHERE name = '{$login}' AND password = '{$haslo}'");
            if(
$query->num_rows 0) {
                
$_SESSION['logged'] = 1;
                return 
1;
            }
            return 
0;
        }
    }

Później sobie includujesz skrypt i możesz się odwołać do metod w ten sposób:
Kod PHP:
//tu include
$cms = new mojCMS;
if(isset(
$_POST['login'], $_POST['password'])) {
 
$cms->loguj($_POST['login'], $_POST['password']);

Mam nadzieję, że kod działa bo go nie sprawdzałem. :P
Obiektówka nie ma tu sensu i uczy w takim przypadku jak powyższy bardzo złej praktyki - bałaganiarstwa.
Klasa od CMSa, jako jedna, która ma też jedynie wewnątrz bazę? Nie, to bez sensu.

Luźna propozycja (niezależnie od wyboru sposobu) - rzuć okiem na PDO zamiast mysqli.
Dzięki za rady i podpowiedzi!
Dzisiaj jestem na etapie przepisywania tego kodu co już miałem na bardziej czytelny i powtarzalny (użycie funkcji). Do szczęścia na ten moment brakuje mi jako tako, kwestii którą poruszyłem w poprzednim poście.

Na przykładzie logowania i wylogowywania.
Mam sobie skrypt do logowania w osobnym pliku - login.php
Mam też skrypt do wylogowywania w logout.php, sęk w tym, że to wydaje się bez sensu.
Moim celem na ten moment jest nauczenie się operowania na linkach, przykładowo
localhost/login.php?action=login
Po wejściu w ten link wywołuje się akcja logowania.
localhost/login.php?action=logout
Ten z kolei - wylogowania.

Później na tym będę chciał oprzeć więcej funkcji, choćby akcje na użytkowniku.
Jak uzyskać taki efekt?

Skrypt logowania:
Kod PHP:
require "inc/functions.php";
    
    
$login $_POST['login'];
    
$password md5($_POST['password']);
    
    
$login htmlentities($loginENT_QUOTES"UTF-8");
    
$password htmlentities($passwordENT_QUOTES"UTF-8");
    
    
    if(
check_if_users_exists($login$password))
    {
        
$_SESSION['logged'] = true;
        unset(
$_SESSION['error']);
        
header('Location: index.php');
    }
    else
    {
        
$_SESSION['error'] = '<br /><span style="color: #FF5656;">Nieprawidłowy e-mail lub hasło</span>';
        
header('Location: login.php');
    } 

logout.php

Kod PHP:
    session_start();
    
    
session_unset();
    
    
header('Location: index.php'); 
Teraz nie do konca rozumiem pytanie, w czym masz problem?
Chce uzyskać taki efekt, że linki:

Cytat:localhost/login.php?action=login
Po wejściu w ten link wywołuje się akcja logowania.
localhost/login.php?action=logout

Będą działały, tj. action=login wykonywało funkcję logowania, a action=logout wylogowywania.

Oba skrypty są obecnie w dwóch osobnych plikach, a moim celem jest zebranie je w jeden - login.php i za pomocą linku - wywołania określonej funkcji.
Kod PHP:
if($_POST['action'] == "login")
{
require 
"inc/functions.php";
    
    
$login $_POST['login'];
    
$password md5($_POST['password']);
    
    
$login htmlentities($loginENT_QUOTES"UTF-8");
    
$password htmlentities($passwordENT_QUOTES"UTF-8");
    
    
    if(
check_if_users_exists($login$password))
    {
        
$_SESSION['logged'] = true;
        unset(
$_SESSION['error']);
        
header('Location: index.php');
    }
    else
    {
        
$_SESSION['error'] = '<br /><span style="color: #FF5656;">Nieprawidłowy e-mail lub hasło</span>';
        
header('Location: login.php');
    } 
}
esleif($_POST['action'] == "logout")
{
session_start();
    
    
session_unset();
    
    
header('Location: index.php'); 
}
esleif(!$_POST['action'])
{
exit;

Znając życie coś oczywistego mi umyka, ale...
$_POST['action'] pobiera wartość z parametru name w inpucie, lub po prostu w formularzu. Musi występować tutaj formularz, który zapostuje te wartości do serwera.
W tym momencie skrypt słusznie wypluwa Undefined index: action in, o ile wartość 'login' mogę ukryć w hidden input w formularzu logowania, to w przypadku gdy wylogowywanie odbywa się poprzez naciśnięcie linku, lub nawet wprowadzenie go w okno przeglądarki, to skrypt nie widzi tego pola.

Próbowałem jeszcze m.in.
Kod PHP:
switch($_GET['action']) {
case 
'logout':
    
logout();


i wywołać to za pomocą linku login.php?action=logout, ale w zasadzie kompletnie nic to nie dawało.
Moj blad, najpierw musimy sprawdzić czy index coś zawiera

Kod PHP:
if(isset($_GET['action']))
{
    
$kacja $_GET['action']; 
    if(
$kacja == "akcja")
    {
        echo 
"Akcja";
    }
    elseif(
$kacja == "akcja2")
    {
        echo 
"Akcja 2";
    }


i masz racje, tu musi być get
NIGDY nie wysyłaj akcji zmieniających stan aplikacji GET'em.

Na stronach gdzie userzy mogą publikować treści, ktoś może zrobić taki HTML:

Kod:
<img src="/index.php?action=logout">

I teraz każde wyświetlenie strony będzie wysyłać GET do tego adresu cichaczem wylogowując zalogowanego usera który ją wyświetlił

Przeglądarki i serwery HTTP domyślnie są skonfigurowane aby próbować ponawiać żądania GET jeśli za pierwszym razem się nie udało. Jak zrobimy przycisk "lubię" robiący GET do "/gdziestam/lajki/" powodujący dodanie punktu dla jakies pozycji, i np. mamy błąd między podniesieniem licznika a zapisem głosu, to przeglądarka/server zrobi kolejny GET do aplikacji, co sprawi że licznik zostanie podniesiony dwukrotnie.
Stron: 1 2