Szukaj na tym blogu

Postaram się przekazać swoje doświadczenia z PHP, oraz innych dziwnych rzeczach, typu MySQL, DB2. Czyli to co umiem. Blogoczytelników o słabych nerwach proszę o nieczytanie tego blogu. Dlaczego? Jeszcze nie wiem. W razie pytań z dziedziny PHP proszę pytać, jest cień możliwości że akurat to wiem. ;)

wtorek, 3 maja 2011

Sprawdzanie poprawności NIP

Kiedyś w napadzie szału musiałem napisać sprawdzanie NIP. Oczywiście w PHP. Bardzo mnie zdziwiło jak ludzie często pamiętają swój NIP z błędem. Przekonałem się o tym jak wdrożyłem to rozwiązanie na serwer. Oto i one:

<?php
$nip = $_POST['nip']; //albo skadś tam wziąć zmienną
if (strlen($nip) == 10) {
$nip_waga = '657234567';
$nip_suma = 0;
if (ereg ('[0-9]{10,10}', $nip) ){
for ($a = 0; $a <= 8; $a++) {
$nip_suma = $nip_suma + (substr ($nip, $a, 1) * substr ($nip_waga, $a, 1));
}
$nip_suma2 = $nip_suma - (intval($nip_suma/11) *11);
if ($nip_suma2 == substr ($nip, -1, 1)) {
echo "Nip OK";
}
else {
echo 'Nip do bani!';
}
}
else {
echo "Nip ma lipną długość.";
}
?>


Tradycji musi się stać zadość, żeby ten przykład zobaczyć. Jest on tu.
Oczywiście dane są nigdzie zapisywane, więc śmiało.

Oczywiście musi być wersja Java Script. Praca z AJAX'em, czystym... nie wiem czy userzy będą nazywali to relaks, jak komputer będzie pisał z upartością maniaka, że NIP który podają jest dobry, ale nie do końca i żeby wpisali ten poprawny.
Oto wersja JS:

if (nip.length == 10) {
nip_waga = '657234567';
nip_suma = 0;
for (a = 0; a <= 8; a++) {
nip_suma = nip_suma + (nip.substr(a, 1) * nip_waga.substr(a, 1));
}
nip_suma2 = nip_suma - (parseInt(nip_suma/11) *11);
if (nip_suma2 == nip.substr(-1, 1)) {
document.getElementById('wynik').innerHTML = "Nip OK";
}
else {
document.getElementById('wynik').innerHTML = 'Nip do bani!';
}
}
else {
document.getElementById('wynik').innerHTML = 'Nip ma lipną długość.';
}


Wersja do klikania jest tu.
W NIP ostatnia cyfra jest sumą kontrolną. Wystarczy 9 odpowiednio pomnożyć, modulo i porównać z ostatnią dziesiątą. Od tej pory źle wpisujący NIP będą karceni.
Jak mnie nawiedzi, wygrzebię jeszcze do sprawdzania poprawności numeru konta bankowego. Dla wstępu napiszę że pełny numer konta zaczyna się on dwóch znaków kraju. W Polsce od PL. Da się to zrobić, kwestia samozaparcia. ;)

środa, 23 marca 2011

Jak można skomplikować skrypt (cz.2)

Kto to w ogóle powymyślał nad silnikiem PHP? Tacy programiści którzy stwierdzili po co czytać miliard książek, dokumentacji, chodzić na drogie szkolenia, jak wystarczy przeczytać kilka moich zdań skleconych powiedzmy że po polsku żeby zorientować się w czym rzecz.
Na początek nie podoba mi się możliwość zmiany zmiennych w klasie. Omijając elegancką funkcję która nam to robi. Nie mówię o wywołanie tekstu też ma wiele do życzenia. Kto to będzie pamiętał że w tej klasie tekst znajduje się w zmiennej text. Więc od początku.

W poprzedniej części zrobiłem klasę tekst i w środku funkcje tekst. To jest właśnie __construct z PHP 4 (dla tych co znają C++ konstrukcja siekierą wyrąbana właśnie stąd). W napadzie szału zmienisz nazwę klasy i trzeba wszystko zmieniać. To bez sensu. Dlatego funkcja tekst będzie nazywała się __construct().
Po po drugie po co pisać jakieś funkcje zmieniające zmienne skoro można to zrobić bez nich. To trzeba zmienić. Dlatego panowie od PHP wymyślili hasła public i private. Kiedy użyjesz private $text już jej nie zmienisz, nie wyświetlisz nic. Ona jest dostępna tylko i wyłącznie w klasie. Wadą tego rozwiązania jest obowiązek napisania funkcji wyświetlającą ją, ale co to dla prawdziwego wojownika. Różni ludzie różnie nazywają ta funkcję np. save, print, echo... kto to spamięta. Na szczęście panowie od PHP nie zasypują gruszek w popiele i wymyślili coś takiego jak __toString() (też C++). Teraz wystarczy zrobić echo $tekst i klasa wyświetli się jak zwykły tekst. Oto przykład.

<?php
class tekst{
private $imie = 'Ala';
private $czynnosc = 'ma';
private $zwierz = 'psa';
private $text = '';

public function __construct() {
$this->text = "{$this->imie} {$this->czynnosc} {$this->zwierz}!";
}
public function zmiana($imie= NULL, $czynnosc = NULL, $zwierz = NULL) {
$this->imie = $imie==NULL ? $this->imie : $imie;
$this->czynnosc = $czynnosc==NULL ? $this->czynnosc : $czynnosc;
$this->zwierz = $zwierz==NULL ? $this->zwierz : $zwierz;
$this->__construct();
}
public function __toString(){
return $this->text;
}
}
$tekst = new tekst;
$tekst->zmiana ('Ola');
echo $tekst;
?>


Jak widzimy wszystkie zmienne są prywatne, wszystkie funkcje są publiczne, zmienna $tekst sama się uzupełnia odpowiednim tekstem, oraz wyświetla się ją też prosto. Czy da się to jeszcze skomplikować? Ależ oczywiście że tak. Napiszmy teraz funkcje która będzie dodawać wykrzyknik. Zrobimy ją prywatną, co by byle kto nie dodawał wykrzykników ile wlezie. Oto i on.

<?php
class tekst{
private $imie = 'Ala';
private $czynnosc = 'ma';
private $zwierz = 'psa';
private $text = '';

public function __construct() {
$this->text = "{$this->imie} {$this->czynnosc} {$this->zwierz}";
$this->wykrzyknik();
}
public function zmiana($imie= NULL, $czynnosc = NULL, $zwierz = NULL) {
$this->imie = $imie==NULL ? $this->imie : $imie;
$this->czynnosc = $czynnosc==NULL ? $this->czynnosc : $czynnosc;
$this->zwierz = $zwierz==NULL ? $this->zwierz : $zwierz;
$this->__construct();
}
public function __toString(){
return $this->text;
}
private function wykrzyknik() {
$this->text .='!';
}
}
$tekst = new tekst;
$tekst->zmiana ('Ola');
echo $tekst;
?>


Teraz prosta rzecz jest wystarczająco złożona. Prywatne zmienne nie pozwalają nam na swobodne zmiany przez kogoś, publiczne funkcje które służą do zmian tekstu w sposób kontrolowany, prywatna funkcja która dodaje wykrzyknik i nie może być wywołana celem siania zamętu.
Czy da się jeszcze to skomplikować? Ależ oczywiście. Jest jeszcze __destruct, __unset, __call, __clone... ale to kiedy indziej.
Kiedyś pisząc zadanie w zawodach, gdzie główną wygraną była praca specjalnie nie użyłem konstrukcji jak w ostatnim przykładzie z nadzieją że facet się zorientuje że se jaja robię, nie zorientował się. Za to Ty możesz wykorzystać ten przykład i możesz mieć moją fuchę. ;)

wtorek, 22 marca 2011

Jak można skomplikować skrypt

Jak można skomplikować se skrypt

W sumie to banalna sprawa, wystarczy przejrzeć niektóre przykłady, ale ja to zrobię w sposób kreatywny. Czyli jak działa coś oczywistego dla doświadczonych. Więc zaczynajmy.
Mamy prosty przykład:

<?php
echo 'Ala ma psa!';
?>


Banalne, ale gdyby ten ciąg znakowy dać jako zmienną.

<?php
$text = 'Ala ma psa!';
echo $text;
?>


W sumie można zaszaleć i zdefiniować stałą.

<?php
define ('TEKST', 'Ala ma psa!');
echo TEXT;
?>


W sumie fajne, ale gdyby pokusić się o... funkcje? Czemu nie, tylko czemu nie dowalić z grubej rury i nie zrobić całej klasy? A co tam, procesory są coraz szybsze...

<?php
class tekst{
var $text = 'Ala ma psa!';
}
$tekst = new tekst;
echo $tekst->text;
?>


Ale skoro mamy już klasę to czemu nie zrobić żeby można było zmieniać ową Alę na kogo innego. Ola będzie dyskryminowana. Zmieńmy to.

<?php
class tekst{
var $text = 'Ala ma psa!';
function zmiana($imie) {
$this->text = "{$imie} ma psa!";
}
}
$tekst = new tekst;
$tekst->zmiana('Ola');
echo $tekst->text;
?>


Ktoś zapyta na grzyba to jakieś $this. Niby proste pytanie. Chodzi o zmienne klasy, a nie funkcji. Jakbyśmy użyli $text, była by to zmienna wewnątrz funkcji, jak tak operujemy zmienną klasy. Nie zmienia to faktu że nadal mam niedosyt. Przecież Ola ma kota? Zróbmy to więc tak.

<?php
class tekst{
var $zwierz = 'psa';
var $imie = 'Ala';
var $text = "Ala ma psa!";
function zmiana_imie($imie) {
$this->imie = $imie;
$this->text = "{$imie} ma {$this->zwierz}!";
}
function zmiana_zwierz($zwierz) {
$this->zwierz = $zwierz;
$this->text = "{$this->imie} ma {$zwierz}!";
}
}
$tekst = new tekst;
$tekst->zmiana_imie('Ola');
$tekst->zmiana_zwierz('kota');
echo $tekst->text;
?>


Specjalnie użyłem tych samych nazw zmiennych, żeby pokazać że są one izolowane. Nie zmienia faktu że czuje jakiś... niedosyt. Czemu to w klasie nie mogę wpisać zmiennych i żeby samo sie układało? Więc dajmy czadu.

<?php
class tekst{
var $imie = 'Ala';
var $czynnosc = 'ma';
var $zwierz = 'psa';
var $text = '';
function tekst() {
$this->text = "{$this->imie} {$this->czynnosc} {$this->zwierz}!";
}
function zmiana_imie($imie) {
$this->imie = $imie;
$this->text = "{$imie} {$this->czynnosc} {$this->zwierz}!";
}
function zmiana_czynnosc($czynnosc) {
$this->czynnosc = $czynnosc;
$this->text = "{$this->imie} {$czynnosc} {$this->zwierz}!";
}
function zmiana_zwierz($zwierz) {
$this->zwierz = $zwierz;
$this->text = "{$this->imie} {$this->czynnosc} {$zwierz}!";
}
}
$tekst = new tekst;
$tekst->zmiana_imie('Ola');
$tekst->zmiana_czynnosc('głaszcze');
$tekst->zmiana_zwierz('konia');
echo $tekst->text;
?>


Na pierwszą myśl przyszło mi nie głaszcze i nie Ola. ;)
Dodałem jeszcze jedną funkcje żeby automatycznie się uruchamiała i robiła nam piękny tekst jak nikt nie wywoła sam funkcji nie wyświetlał pustego.
Czy można bardziej zamotać? Zamotać da się, ale za to będzie mniej lini.

<?php
class tekst{
var $imie = 'Ala';
var $czynnosc = 'ma';
var $zwierz = 'psa';
var $text = '';
function tekst() {
$this->text = "{$this->imie} {$this->czynnosc} {$this->zwierz}!";
}
function zmiana($imie= NULL, $czynnosc = NULL, $zwierz = NULL) {
$this->imie = $imie==NULL ? $this->imie : $imie;
$this->czynnosc = $czynnosc==NULL ? $this->czynnosc : $czynnosc;
$this->zwierz = $zwierz==NULL ? $this->zwierz : $zwierz;
$this->tekst();
}
}
$tekst = new tekst;
$tekst->zmiana ('Ola');
echo $tekst->text;
?>


Teraz jest jedna funkcja zmieniająca wszystko. Jeżeli będzie jeden parametr, drugi i trzeci będzie NULL i wstawi się wartość domyślna. Poza tym w funkcji zmiana jest wywoływana funkcja tekst, co by jej nie pisać dwa razy. Jeżeli nie wywołamy funkcji zmiana, będzie wartość domyślna.

Ciąg dalszy nastąpi matactwa klasy, tak jej zostawić nie można.

czwartek, 17 marca 2011

Sprawdzanie poprawności PESEL.

Często gęsto człowiek boryka się czy dany PESEL jest prawidłowy. Oto prosty przykład jak można sprawdzić czy delikwent aby nie konfabuluje w dziedzinie PESEL.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<title>Pesel checker</title>
<meta name="AUTHOR" content="plx">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<strong>Sprawdzacz peseli</strong><br>
<form action="pesel_check.php" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="pesel"> <input type="submit" value="check">
</form><br>
<?php
if (isset($_POST['pesel'])) {
$pesel = trim($_POST['pesel']);
$pesel_waga = '13791379131';
$pesel_suma = 0;
if (strlen($pesel) == 11) {
for ($a = 0; $a <= 10; $a++)
$pesel_suma = $pesel_suma + (substr ($pesel, $a, 1) * substr ($pesel_waga, $a, 1));
if (substr ($pesel_suma, -1, 1) == '0')
echo "Pesel prawidłowy.";
else
echo "Pesel jest nieprawidłowy.";
}
else
echo "Pesel ma złą długość.";
}
?>
</body>
</html>



Jak działa, dostępny jest TU.
Dla tych co uważają że serwer nie powinien zajmować się takimi bzdetami i niech sprawdza w JS po stronie klienta pamięta, że zawsze znajdzie się ktoś kto wyłączy JS, albo spreparuje własne dane i wyśle, więc i tak serwer musi sprawdzać poprawność danych.

Oto prosty przykład jak to samo można przenieść do JS.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<title>Pesel checker</title>
<meta name="AUTHOR" content="plx">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
function pesel_check(pesel) {
var pesel_waga = '13791379131';
var pesel_suma = 0;
if (pesel.length = 11) {
for (a = 0; a <= 10; a++)
pesel_suma = pesel_suma + (pesel.substr(a, 1) * pesel_waga.substr(a, 1));
pesel_suma_str = pesel_suma.toString();

if (pesel_suma_str.substr(-1, 1) == '0')
document.getElementById('wynik').innerHTML = 'Pesel prawidłowy.';
else
document.getElementById('wynik').innerHTML = 'Pesel jest nieprawidłowy.';

}
}
</script>
</head>
<body>
<strong>Sprawdzacz peseli</strong><br>
<input type="text" name="pesel" onchange="pesel_check(this.value);">
<br>
<div id="wynik">Tu będzie wynik, albo i nie.</div>
</body>
</html>



Można go przetestować TU.

Te przykłady są na tyle proste i oczywiste, że każdy bez większych kłopotów użyje sobie gdzie chce i jak chce.

Powodzenia.

PS. Możecie śmiało sprawdzać, wyniki nigdzie nie są zapisywane zgodnie z ustawą o ochronie danych osobowych, bla bla bla. Niech nikogo nie zmyli. Sam PESEL jest daną osobową.

wtorek, 15 marca 2011

Sklep w osCommerce

Postaram się opisać bolączki jakie mogą Cię spotkać podczas używania wyżej wymienionego skryptu i nie zamierzam być delikatny w dziedzinie dziur. Jest ich tylko od cholery. Nie przejmuj się. Mogło być gorzej.

Zakładam że masz już zainstalowane i skonfigurowany sklep. Instalacja jest banalna, więc nie będę jej opisywał. Poza tym pełno jest stron z mniej czy bardziej szczegółowym opisem.

O ile znalazłeś na forach na forach że musisz wyrzucić pliki do „Eksplorator Plików”, oraz „Definiowanie Języków”, bo znajduje się tam krytyczna dziura pozwalająca rozwalić Ci cały serwis. Jednym z objawów włamu jest wpis w logi:

"GET /admin/includes/languages/english/modules/newsletters/sh.php
?call=proxy&data=http://www.google.com/search?num=100%26hl=en%26safe=off%
26client=opera%26hs=moz%26rls=en%26q=test%26lr=lang_en%26aq=f%26aqi=%26aql
=%26oq=%26gs_rfai=%26tbs=clue:1%26 HTTP/1.1" 404 335 "http://domena.com
/admin/includes/languages/english/modules/newsletters/sh.php?call=proxy&data
=http://www.google.com/search?num=100%26hl=en%26safe=off%26client=opera%26hs=moz%
26rls=en%26q=test%26lr=lang_en%26aq=f%26aqi=%26aql=%26oq=%26gs_rfai=%26tbs=
clue:1%26" "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.6.30 Version/10.62"

Swoją drogą, zawsze wpis jest Opera. Ciekawe czemu?
Tu już biedny robot nie ma dojścia do tego pliku, bo jakiś cham wykasował, ale to jest plik który Ci napsuje krwi i może być wszędzie. Drugi objaw jest .htaccess z dziwnymi wpisami. Powywalaj je, a gdzie były powstawiaj oryginalne.

Naprawę tych plików daruj se. Ona nie jest jedna. Jeszcze nie namierzyłem który plik, ale pozwala założyć admina przez niepowołane osoby. Moja rada jest prostsza. Zmień katalog admin na jakikolwiek, byle nie administrator i administrators. Na przykład zarzadzanie, adminowanie, ustawnictwo, a nawet zarzondzanie. Wiem, zarządzanie piszę się przez ą, ale włamywacze mogą tego nie wiedzieć. Im bardziej „szalona” nazwa katalogu, tym lepiej.

Zmieniłem i co dalej?
W

<twoja_szalona_nazwa>/includes/configure.php znajduje się klucz do sukcesu. Mianowicie:
define('DIR_WS_ADMIN', '/admin/');


zamień na:

define('DIR_WS_ADMIN', '/<twoja_szalona_nazwa>/');




define('DIR_FS_ADMIN', '/<katalog_twojego_sklepu>\AdmiN');


zmień na:

define('DIR_FS_ADMIN', '/<katalog_twojego_sklepu>\<twoja_szalona_nazwa>');



Możesz spać spokojne. Na razie. Jeżeli znajdę jakąś inną dziurę, która jest w sklepie, nie omieszkam tego napisać.

Moim drugim usprawnieniem jeszcze przed naprawą wyżej wymienionych plików jest zmiana katalogu images. W pliku konfiguracyjnym admina zmieniłem z:

define('DIR_FS_CATALOG_IMAGES', DIR_FS_CATALOG . 'images/');


na

define('DIR_FS_CATALOG_IMAGES', DIR_FS_CATALOG . 'obrazunie/');


W pliku konfiguracyjnym sklepu zostawiłem po staremu. Powiecie że nie działa bo nie ma ani jednego obrazka. I tak ma być. Tu trochę jadu dla programistów. Co za poroniony pomysł wrzucać obrazki layoutu ze zdjęciami produktów?
Tak tego zostawić nie można więc potrzebujesz mały wpis do .htaccess:

Options +FollowSymLinks
RewriteEngine On
RewriteRule images/(.*\.(png|gif|jpg)) obrazunie/$1 [L]
RewriteRule obrazunie/(.*\.(sh|txt|php)) tych.php/$1 [L]



W pliku tych.php napisz co myślisz o wszelkich włamaniach, oraz rodzinach włamywaczy, oraz co Cię dziś zdenerwowało. Ogólnie ulżyj se. ;) Bynajmniej tych to nie jest skrót od Tychów, tam są dwa wyrazy. ;)

poniedziałek, 12 kwietnia 2010

Funkcja mysqli

Oto najprostsza metoda podłączenie się do MySQL'a i zadanie pytania i otrzymanie stosownych odpowiedzi.


<?php
$link = mysql_connect("localhost", "franek", "franek12");
mysql_select_db("franek");
$wynik = mysql_query("SELECT * FROM tabela WHERE id={$_GET['id']}");
$rekord = mysql_fetch_array($wynik, MYSQL_NUM);
echo "Wynik {$wynik[0]}";
mysql_close($link);
?>


Ten wzór pokutuje od zawsze. Co jest w mim źle? Szybciej co jest w nim dobrze. Działać będzie działać, ale czemu można tu się włamać.
Pierwszym najważniejszym błędem jest id={$_GET['id']}.
Zawsze można skazić dane tak, żeby naszego spodziewanego ID od 0 do nieskończoności jest wrzucenie czegoś co wywali nam bazę w kosmos, albo i jeszcze dalej. Druga rzecz, nigdy nie nazywaj zmiennej tak jak nazwa w bazie. Po co ułatwiać innym włamywanie się? Nigdy nie używaj * w zapytaniach. Załóżmy że zmieni Ci się liczba kolumn i co wtedy?

Teraz mnie więcej wiadomo co źle, teraz weźmy się jak to zrobić dobrze. O ile dobrze istnieje. Powiedzmy poprawnie.

Zacznijmy od podłączenia do bazy danych.


<?php
$link = @mysqli_connect('localhost', 'użytkownik', 'hasło', 'nazwa_bazy_danych');

if (!$link) {
die('Błąd połączenia: ' . mysqli_connect_errno());
}
?>



Dodam tu swoje 5 groszy, żeby użytkownik był inny niż nazwa bazy. Pełnią szczęścia był by jeden użytkownik z okrojonymi prawami dla serwisu, a drugi do administrowania bazą.
Szczytem finezji było przekierowanie na inną stronę pod tytułem "Serwis się popsuł", a błąd zapisać w logach Apache, albo gdzie indziej. Byle nie w bazie, która jak wiadomo z jakiś przyczyn jest niedostępna. Można wysyłać błąd na komórkę, albo e-mailem. To już musi być bardziej zaawansowana procedura, zwłaszcza przy serwisie często odwiedzanym. Wtedy przy każdym kliknięciu administrator dostanie SMS, albo e-mail. W efekcie skrzynka zapcha się mu po 20 minutach, a telefon lub jego właściciel zwariuje o minute później.

Przy mysqli_connect jest umieszczony @. Jeżeli w php.ini jest ustawione wyświetlanie błędów w skrypcie, @ zapobiega temu.

Bardziej elegancką wersją tego samego jest zmajstrowanie sobie klasy. Brzmi bardzo groźnie, ale nie taki diabeł straszny...


<?php
$klasa = @new mysqli('localhost', 'użytkownik', 'hasło', 'nazwa_bazy_danych');

if ($klasa->connect_error) {
die('Connect Error: ' . $klasa->connect_error);
}
?>


Na pierwszy rzut oka wygląda tak samo. Nie do końca.
Dla tych co nie wiedzą co to jest klasa szybkie objaśnienie. Klasa jest zbiorem funkcji tworząca obiekt z własnymi zmiennymi, które są niewidoczne na zewnątrz. Nie ma problemu kiedy się użyje tej samej zmiennej w różnych klasach.

To co z tym obiektem dalej? W zasadzie można zrobić jakiegoś SELECT'a w bazie, wyglądać będzie to tak:



<?php
$wynik = FALSE;
$objekt = FALSE;

$baza = new mysqli("localhost", "użytkownik", "hasło", "baza");
if (mysqli_connect_errno()) die("Błąd bazy.");
$baza->set_charset('utf8');
$typ_pracownika = $baza->real_escape_string($_GET['kto']);
$pytanie = "SELECT `imie`, `nazwisko` FROM `pracownicy` WHERE `typ`='{$typ_pracownika}'";

if ($wynik == $baza->query($pytanie)) {
while ($objekt = $wynik->fetch_object()) {
printf ("Imię: %s nazwisko: %s <br>\n", $obj->imie, $obj->nazwisko);
}
$pytanie->close();
}
$pytanie->close();
?>



$wynik i $obiekt ma specjalne na początku wpisane FALSE, w razie jak by ktoś kombinował z przemyceniem danych.
set_charset jest tylko i wyłącznie po to, co by klient z bazą gadał UTF-8, a nie LATIN1. Po kilku insertach z wyrazami "gżegżółka" można ciut zblednąć widząc w PHPMySQLAdmin'ie krzaczki w miejscu polskich liter.
Nie używam w zapytaniu *, żeby panować nad pytaniem. Ktoś zmieni nazwę kolumny i pół roku szukania i narzekania "czemu nie wyświetla się! Działało jeszcze wczoraj!" tak będzie błąd "nieznana nazwa".
Porada dla początkujących w MySQL. Wszystkie nazwy kolumn aliasów tabel baz danych powinny być w ` `, a wartości w ' '. Po pierwsze czytelniejszy SQL, po drugie jest jasność dla interpretera (na posty typu bez tego też działa, nie odpisuje).
real_escape_string jest elegancką funkcją wstawiającą m.i. / przed ', co by nam ktoś nie skaził danych.Zawsze można powiedzieć że w niektórych MySQL ta funkcja ma luki. W sumie to fakt, nigdy nie wiadomo na jakim będzie to serwerze działało i jaką wersją bazy. Może wtedy wykorzystać STR_REPLACE, wpakować tablice co na co ma wymienić... albo użyć coś bardziej pokrętnego, czyli PREPARE STATEMENT. A oto i on!


<?php
$baza = new mysqli("localhost", "użytkownik", "hasło", "baza");
if (mysqli_connect_errno()) die("Błąd bazy.");
$baza->set_charset('utf8');
$baza = $db->prepare("SELECT `imie`, `nazwisko` FROM `ludzie` WHERE `ksywa` = ? LIMIT 1");
$baza->bind_param('s', $_GET['nick']);
$baza->execute();
$baza->bind_result($f_name, $s_name);
$baza->fetch();
$baza->close();
?>



To jest przykład wyrwany z jakiegoś dawnego wiekopomnego dzieła, jak mnie jeszcze źli ludzie nie terroryzowali Java.
W SQL tam gdzie jest pierwszy znak zapytania (w tym przypadku i ostatni) będziemy wstawiali zmienną. Czemu nie w ''? Nie potrzeba. bind_param podstawia elegancko coś wysłane do skryptu metodą GET, a s sygnalizuje że to jest STRING. Jak wstawimy I będzie INTEGER. jeszcze jest d jak double i bjak BLOB. Duży binarny obiekt (np. kompromitujące kogoś zdjęcie). Jak ktoś ma dwa znaki zapytania w zapytaniu lub więcej musi w pierwszym parametrze nawstawiać literki co to za zwierz, a dalej po przecinku w odpowiedniej kolejności powpisywać wartości. Na przykład:



$baza->bind_param('iss', $id, $imie, $nazwisko);



I jest szczęśliwy że działa.

Execute wiadomo.

bind_result wrzuca w poszczególne zmienne wartości z zapytania.

fetch przechwytuje. W tym przypadku spodziewamy się jednego osobnika. Po pierwsze NICK który teoretycznie powinien być unikalny, po drugie żeby baza za nas nie musiała kombinować jak nie ma klauzuli unikalności z jakiś przyczyn, jak znajdzie jednego delikwenta, niech dalej się nie męczy.
Jeżeli jednak chcemy mieć więcej rekordów niż jeden umieszczamy fetch w pętli.

Teraz można już coś z bazą robić. Jest tam parę zgrzytów i można by było zrobić lepiej, ale ktoś może mnie tez poprawiać, w napadzie szału wyśmiać gdzieś na blogu.

PS. Ci co szukają w wyszukiwarce przykładów do CV, albo są po rozmowie kwalifikacyjnej i muszą teraz błysnąć intelektem w jakimś przykładzie przez siebie stworzonym mam ostrzeżenie. Zmieniajcie choć nazwy zmiennych. Przyszły pracodawca na pewno to znajdzie w w sieci, albo przypadkowo zna te przykłady od dawna. ;)

poniedziałek, 5 kwietnia 2010

Funkcja ECHO

Ostatnio odkryłem funkcje ECHO. Działa rewelacyjnie. Piszę:

echo "Ala ma psa";
echo 'Ala ma kota';

I tu się zaczynają schody, wyższość świąt Bożego Narodzenia, nad świętami Wielkiej nocy. W " " działa wolniej i nie można używać, za to w ' ' nie można używać zmiennych takich jak

echo "Ala ma {$ilosc} kotów";

Za to używając pojedynczych trzeba używać składni:

echo 'Ala ma '.$ilosc.' kotów';

Oczywiście wiadoma sprawa, w cudzysłowach jest zaledwie miliard wolniejszy niż w apostrofach.

Dobra, dość tych mitów.
W cudzysłowach faktycznie działa wolniej.  Problem w tym, że różnica jest w błędzie statystycznym i nie ma czym se głowy zawracać. Jedna ważna rzecz, trzeba zmienne pisać w klamrach. Wiem że działa bez, ale czasem zdarzają się dziwne rzeczy, zwłaszcza jak używa się tablic do wyświetlenia.

Jest jeszcze jedna zdobycz techniki:

echo <<<EOF
Ala ma {$ilosc} kotów.
Ola "miała" {$psy['ola']} psów.
echo "to mój przykład z PHP";
EOF;

Działa w sposób banalny, widzi <<<, po tym jest jakiś ciąg znaczków. W tym przypadku EOF. Jeżeli ktoś mi zada pytanie dlaczego EOF (End of File), to powiem że nie wiem. Zamiast EOF można użyć dowolny ciąg znaków. Chodzi o to, żeby interpreter wiedział kiedy zakończyć wyświetlanie. Dobrze może być:

echo <<<NIENAWIDZE_KACZEK
Ala ma {$ilosc} kotów.
Ola "miała" {$psy['ola']} psów.
echo "to mój przykład z PHP";
NIENAWIDZE_KACZEK;

Ważne żeby na początku i na końcu będzie ten sam ciąg. W środku może być dokładnie wszystko. No może z wyjątkiem równań różniczkowych.

Kiedy robi się aplikację, w której liczy się każdy takt zegara (coś, co jest znane tylko na demo scenie), można wydziwiać która metoda jest lepsza.
W tej chwili jest ważne co jest wygodniejsze w tej chwili w danym miejscu.