Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Funkcja do sprawdzania treści z formularza
andrzejt17
post
Post #1





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 24.06.2009
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Proszę was o ocene skryptu pod kątem przydatności i funkcjonalności oraz proszę o wskazówki :) Czyli co zmienić, czego nie używać itp :)

  1. <?php
  2. // (kod)
  3.  
  4. function checkString($name, $value, $length, $type='all') {
  5. function showAlert($msg) {
  6. print ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  7. <script type="text/javascript">
  8. alert("'.$msg.'");
  9. </script>';
  10. }
  11.  
  12. $value = strtolower(makeSafe($value));
  13. $charsToReplace = array('ą', 'ż', 'ź', 'ś', 'ę', 'Ć', 'ń', 'ł', 'ó', 'Ą', 'Ż', 'Ź', 'Ś', 'Ę', 'Ć', 'Ń', 'Ł', 'Ó');
  14. $valueToCount = str_replace($charsToReplace, 'x', $value);
  15. $length = explode('-', $length);
  16. if(strlen($length[0]) > 0 && strlen($length[1]) > 0) {
  17. $min = $length[0];
  18. $max = $length[1];
  19. } else {
  20. echo 'checkString length arg failed';
  21. }
  22. if(strlen($valueToCount) == 0) {
  23. showAlert('Pole \''.$name.'\' jest obowiązkowe, nie może być puste.');
  24. return false;
  25. } elseif(strlen($valueToCount) <= $min) {
  26. showAlert('Liczba znaków w polu \''.$name.'\' jest za mała. Wymagana minimalna liczba znaków: '.$min.'.');
  27. return false;
  28. } elseif(strlen($valueToCount) >= $max) {
  29. showAlert('Liczba znaków w polu \''.$name.'\' jest za duża. Wymagana maksymalna liczba znaków: '.$max.'.');
  30. return false;
  31. }
  32.  
  33. if($type == 'n') {
  34. if(!preg_match ('/^[0-9]+$/', $value)) {
  35. showAlert('Zawartość pola \''.$name.'\' musi być liczbą.');
  36. return false;
  37. }
  38. } elseif($type == 'tl') {
  39. if(!preg_match ('/^[0-9A-Za-z._-]+$/', $value)) {
  40. showAlert('Zawartość pola \''.$name.'\' może zawierać cyfry, małe i duże litery bez polskich znaków diakrytycznych oraz znaki specjalne: (._-)');
  41. return false;
  42. }
  43. } elseif($type == 'm') {
  44. if(!preg_match ('/^([0-9a-z]([-.\w]*[0-9a-z])*@(([0-9a-z])+([-\w]*[0-9a-z])*\.)+[a-z]{2,6})$/i', $value)) {
  45. showAlert('Podany adres email jest nieprawidlowy.');
  46. return false;
  47. }
  48. }
  49.  
  50. return true;
  51. }
  52.  
  53. // (kod)
  54. ?>


Do tego funcja makeSafe();
  1. <?php
  2. // (kod)
  3.  
  4. function makeSafe($string) {
  5. $string = stripslashes($string);
  6. }
  7. $string = mysql_real_escape_string(trim($string));
  8. $string = htmlspecialchars($string);
  9. $string = str_replace("\r\n", "", $string);
  10.  
  11. return $string;
  12. }
  13.  
  14.  
  15. // (kod)
  16. ?>



Wywyłanie:
  1. <?php
  2. // (kod)
  3. // sprawdzenie testowo jednego pola z formularza
  4.  
  5. $imieUsera = makeSafe($_POST['imie']);
  6. $nazwiskoUsera = makeSafe($_POST['nazwisko']);
  7.  
  8. if(checkString('Imie', $imieUsera, '3-10', $type='tl') && checkString('Nazwisko', $nazwiskoUsera, '3-10', $type='tl')) {
  9. echo 'Wszystko ok';
  10. } else {
  11. echo 'Coś lipa';
  12. }
  13.  
  14. // (kod)
  15. ?>


Ten post edytował andrzejt17 13.05.2011, 17:11:18
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 8)
Zyx
post
Post #2





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Czego nie używać? Na pewno nie kodu powyżej. Twój kod przypomina serię z karabinu maszynowego puszczoną na oślep w tłum, przy czym jest duża szansa, że w tłumie nikt nie zostanie nawet ranny, a zginie od kuli jakaś staruszka 10 ulic dalej. Umiesz używać karabinu, ale nie umiesz nim jeszcze strzelić tam, gdzie chcesz. Musisz się nauczyć, że nie wolno wrzucać wszystkiego do jednego worka, bo to gwarantuje kłopoty. A u Ciebie w tym momencie funkcja robi wszystko:

- sprawdza długość tekstu
- sprawdza poprawność znaków
- sprawdza e-mail (!)
- wypisuje błędy
- generuje kod HTML

jeszcze tylko brakuje, by pranie robiła przy okazji. Bardzo nieumiejętnie posługujesz się dostępnymi w PHP funkcjami. Znajomość rozszerzeń i możliwości języka leży na całej linii:

  1. $value = strtolower(makeSafe($value));
  2. $charsToReplace = array('ą', 'ż', 'ź', 'ś', 'ę', 'Ć', 'ń', 'ł', 'ó', 'Ą', 'Ż', 'Ź', 'Ś', 'Ę', 'Ć', 'Ń', 'Ł', 'Ó');
  3. $valueToCount = str_replace($charsToReplace, 'x', $value);


ŹLE - masz mb_strlen() (już pomijam fakt, że w tych trzech linijkach jest błąd, ale o tym dalej)

  1. $length = explode('-', $length);
  2. if(strlen($length[0]) > 0 && strlen($length[1]) > 0) {


ŹLE - masz tablice!

  1. if(!preg_match ('/^[0-9]+$/', $value)) {
  2. showAlert('Zawartość pola \''.$name.'\' musi być liczbą.');
  3. return false;
  4. }


ŹLE - masz ctype_digit()

  1. if(!preg_match ('/^[0-9A-Za-z._-]+$/', $value)) {


ŹLE - masz ctype_alnum()

  1. if(!preg_match ('/^([0-9a-z]([-.\w]*[0-9a-z])*@(([0-9a-z])+([-\w]*[0-9a-z])*\.)+[a-z]{2,6})$/i', $value)) {


ŹLE - masz filter_var()

  1. function makeSafe($string) {
  2. $string = stripslashes($string);
  3. }
  4. $string = mysql_real_escape_string(trim($string));


ŹLE - primo, dobrze napisany skrypt powinien zakładać, że dane wejściowe nie są wyescape'owane i escape'ować je TYLKO W RAZIE POTRZEBY. Ponadto wytłumacz mi, jaka jest logika robienia najpierw stripslashes() tylko po to, by chwilę później zrobić mysql_real_escape_string()? I wrócę teraz jeszcze do wspomnianego błędu: nie myślisz podczas kodowania. Spójrz na przykład: przed wywołaniem checkString() przepuszczasz wartość przez makeSafe(). A co robisz w checkString()? Przepuszczasz ją przez tę funkcję ponownie.
Go to the top of the page
+Quote Post
thek
post
Post #3





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Ogólnie z tym co napisałeś Zyx się zgadzam, ale doczepię się szczegółów:
1) ctype_alnum walnie true dla a-z0-9, ale w regexpie są jeszcze _.-, tak więc ctype_alnum tutaj nie może być użyty.
2) filter_var do sprawdzania maila, z tego co gdzieś w necie wyczytałem, jest zawodną funkcą i nie należy mu zbytnio ufać. Stąd wyrażenie regularne jest pewniejsze niż on i nawet w frameworkach jest to faworyzowane rozwiązanie. Nie wierzyłem do czasu, gdy mi także się zdarzyło, że wywalił false na poprawnym mailu i od tamtego czasu zarzuciłem używanie tej funkcji na rzecz regexp.
3) rozumiem sprawdzanie gpc z racji faktu, iż nigdy na początku nie wiemy, na jaki hosting się trafi i co ma w konfigu włączone a co nie. Jeśli z jakiejś głupiej przyczyny magic_quotes są włączone, to podczas obróbki i ponownego wkładania danych do formularza może zakończyć się niemiłymi niespodziankami. Stąd rozumiem czemu piszesz o tym, że dane powinny być nie escape'owane. Inna sprawa, że magic_quotes używają do escape'owania addslashes jeśli dobrze pamiętam. A ta funkcja jest dziurawa (IMG:style_emoticons/default/wink.gif) "Zastąpienie" jej poprzez mysql_real_escape_string jest pewniejsza.

Ogólnie jednak się zgodzę, że jest to pomieszanie z poplątaniem. Zwłaszcza patrząc na walenie mety w print co jest, delikatnie mówiąc, chybione.
Go to the top of the page
+Quote Post
andrzejt17
post
Post #4





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 24.06.2009
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Panowie, dziękuję za wskazówki (IMG:style_emoticons/default/smile.gif) Jednak nasuwa mi się kilka pytań.

Do Zyx:

1. "Musisz się nauczyć, że nie wolno wrzucać wszystkiego do jednego worka, bo to gwarantuje kłopoty." Zapewne chodzi o funkcję checkString(). Czy jest sens robienia osobnej funkcji dla sprawdzania każdego typu danych? Np. checkNum(), checkMail() itd? Po to właśnie jest jeden z argumentów w checkString() by ustalić pod jakim kątem ma sprawdzać naszego stringa. Funkcja do tego celu jest mi niezbędna bo moja strona przewiduje kilka formularzy i uciążliwe byłoby pisanie tego samego w kilku miejscach. Jeśli będą takie możliwości w php to napiszę funkcję od prania ;D

2. O mb_strlen() nawet nie słyszałem (IMG:style_emoticons/default/haha.gif) Zakładam, że policzy mi ona cyferki (IMG:style_emoticons/default/wink.gif) Pytanie tylko czy musze podawać argument z kodowaniem znaków i jeśli tak to jaki będzie dla utf-8? ut8? (IMG:style_emoticons/default/snitch.gif)

3. "ŹLE - masz tablice!" Chodzi o to, że gdy nie będzie nic przed '-' albo po to wtedy będę miał tylko jedną tablice? Wtedy można tylko sprawdzić, czy wybrana tablica istnieje a nie sprawdzać czy jej wartość jest większa od 0, dobrze rozumuję?

4. ctype_digit(), po tym co napisał thek jednak zostanę przy swoim rozwiązaniu.

5. ctype_alnum(), chodzi mi też o znaki" _.- które mogą być użyte np. w loginie.

6. filter_var(), również zostanę przy swoim rozwiązaniu (thek).

7. Escapować tylko w razie potrzeby? Tzn wtedy, kiedy np. chce dodać wartość do bazy? Fakt, z tym escapowaniem przesadziłem dlatego uszczupliłem funkcję makeSafe() i używał jej będę tylko raz, przy pobieraniu treści z POST'a. stripslashes() poszedł w kosz.


Do: thek

Funkcja sprawdzania formularza jest wywoływana przed <html> w dokumencie co oznacza, że polskie znaki zwracane w print przez funkcję zostaną wyświetlone z krzakami (meta w head). Dlatego ta meta tam siedzi bo już stamtąd zwracam komunikat userowi, nie mam pomysłu na coś lepszego (nie chce tego robić echem).


== EDIT ==
Acha, jeszcze jedno (IMG:style_emoticons/default/smile.gif) Jak by ktoś pytał, showAlert() jest wewnątrz chechString() dlatego, że tylko tam mi ona potrzebna. Do zwracania reszty komunikatów używam innej funkcji:
  1. <?php
  2.  
  3. function jsAlert($errorCode, $url='0') {
  4. switch($errorCode) {
  5. case 100:
  6. $message = 'Ta operacja wymaga podniesienia upranień. Zaloguj się.';
  7. break;
  8. case 101:
  9. $message = 'Nie masz uprawnień do tej części serwisu. Zaloguj się.';
  10. break;
  11. // dalsze kody błędów
  12. }
  13.  
  14. if($url == '0') {
  15. print ' <script type="text/javascript">
  16. alert("'.$message.'");
  17. </script>';
  18. } else {
  19. print ' <script type="text/javascript">
  20. if(confirm("'.$message.'")) {
  21. window.location = "'.$url.'"
  22. } else {
  23. window.location = "'.$url.'"
  24. }
  25. </script> ';
  26. }
  27. }
  28.  
  29. ?>


Kod pewnie też kaszana ale nie mam lepszego pomysłu na zwracanie komunikatów. Ten mi wiernie służył i nigdy nie zawiódł (IMG:style_emoticons/default/wink.gif)

== EDIT2 ==
Jak się właśnie okazało kod nie spełnia swojej roli tak jak bym tego chciał. Okazuje się, że:
  1. if(checkString('nazwa1', 'wartosc', '2-10') && checkString('nazwa2', $wartosc2, '2-10')) {
  2. // akcja
  3. }

nie przynosi żądanego rezultatu. Jeśli w if mam tylko jedno wywołanie to działa jak należy, jeśli dwa czy więcej to checkString() nie robi nic (pusta strona).

Ten post edytował andrzejt17 13.05.2011, 23:47:50
Go to the top of the page
+Quote Post
thek
post
Post #5





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Dziwisz się? IF to operacja logiczna i wystarczy jeden false a cały warunek idzie w piach, bo używasz && czyli I logicznego. A zobacz kiedy to jest prawdziwe... Tylko gdy wszystkie warunki są prawdziwe. Jedna pierdółka na false i wszystko leży.

Dorzućmy odpowiedzi Ci... Czy jest sens stosować oddzielnie funkcje? Tak! Ponieważ wtedy masz je bardziej uniwersalne. Zamiast potem pisać pierdylion funkcji lub wywoływać jedną z różnymi, nie zawsze sensownymi parametrami, posługujesz się kilkoma w konkretnych sytuacjach. I tak musisz przejść przez nią całą i sprawdzić X warunków IF i jako parametr w wywołaniu dla tych miejsc które opuszczasz ustawić "tego nie rób". Innymi słowy: mniejsza funkcja -> mniej roboty. A czy jest sens robić jeden kombajn i pamiętać co jaki parametr znaczy czy prościej zrobić mniejsze i wyspecjalizowane funkcje, które nie tylko w tym jednym miejscu wykorzystasz, ale w dowolnym fragmencie?

ctype_digit akurat działa dobrze, poza tym nic o niej nie pisałem (IMG:style_emoticons/default/smile.gif)

Jeśli printujesz coś PRZED html, to chyba zupełnie nie rozumiesz, że tak nie powinno się robić. dokument html powinien się znacznikiem html zaczynać czy też specyfikacją DTD i nic nie ma prawa przed nim być wypisane. To zwyczajny błąd. To co chcesz osiągnąć, czyli wyświetlenie komunikatu błędu wraz z przekierowaniem na określoną stronę, rozwiązuje się zupełnie inaczej... Samą walidację także podejrzyj w nieco innych stronach, bardziej profesjonalnych - jakieś darmowe cms choćby.
Go to the top of the page
+Quote Post
andrzejt17
post
Post #6





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 24.06.2009
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Czyli jestem zmuszony robić coś w tym stylu:
  1. if(strlen($wartosc) < 3) {
  2. echo 'za malo znakow';
  3. } elseif(strlen($wartosc) > 15) {
  4. echo 'za duzo znakow';
  5. } elseif(!ctype_digit($wartosc)) {
  6. echo 'nie jest liczba';
  7. }

A chciałem ciachnąć fały formularz w jednym if'ie (IMG:style_emoticons/default/wink.gif) W sumie tak to nawet lepiej, przejrzyściej (IMG:style_emoticons/default/wink.gif)

Przekonałeś mnie z tymi osobnymi funkcjami. Faktycznie lepiej jest napisać funkcję do jednej konkretnej rzeczy a nie jedną do wszystkiego.

Z tym ctype_digit() faktycznie, nie pisałeś. Musiało mi się coś pomieszać, nie spałem tamtą noc więc zwyczajnie już nie ogarniałem (IMG:style_emoticons/default/wink.gif)

Jeśli coś printuje, jakiś kod html, no dynamiczny formularz czy jakiś inny kod to oczywiście funkcję, która to robi wywołuję już po znaczniku <body> wiec wszystko jest cacy zachowane. Inaczej to wygląda w wypadku zwracania komunikatu userowi przez alert w js. Jakimś cudem to działa na moim hostingu, on jakby za mnie wcześniej dopisuje html, body i całą resztę to nawet jak je pousuwam ze swojej strine to i tak wszystko hula (hosting dołącza reklamy więc pewnie dlatego).

Tak czy inaczej będę musiał pomyśleć nad jakąś metodą zwracania komunikatów userowi. Chce to zrobić w alercie w js bo jest najprościej. Może jak bd printował alerta to może tam dorzucę znaczniki niezbędne w html byle tylko to wyświetlić. (IMG:style_emoticons/default/wink.gif)
Go to the top of the page
+Quote Post
thek
post
Post #7





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Co do długości... Nie pomyślałeś o metodzie po prostu walidującej długość jako zakres min, max?
valid_length( $string, $min = false, $max = false)

Jeśli będzie błąd, zwróć komunikat/y błędu, jeśli OK zwróć TRUE. Przy sprawdzeniu zrób === TRUE (IMG:style_emoticons/default/smile.gif) To tylko jedna z implementacji.
  1. function valid_length( $string, $min = false, $max = false) {
  2. $error = array();
  3. $valid_min = false;
  4. if($min && ctype_digit($min) && $min > 0 ) {
  5. $valid_min = true;
  6. if( mb_strlen($string ) < $min ) {
  7. $error[] = 'Ciąg za krótki. Wymagane '.$min.' znaków';
  8. }
  9. }
  10. if($max && ctype_digit($max) && $max > 0 ) {
  11. if( mb_strlen($string ) < $max ) {
  12. $error[] = 'Ciąg za długi. Maksymalnie '.$max.' znaków';
  13. }
  14. if($min == false || $valid_min ) {
  15. if( $max - (int)$min < 0) {
  16. $error[] = "Minimum jest więkse niż maximum.";
  17. }
  18. }
  19. }
  20. if( count( $error ) > 0 ) {
  21. return $error;
  22. } else {
  23. return true;
  24. }
  25. }
Oczywiście pewne rzeczy można rozwiązać ładniej poprzez choćby rzucenie wyjątku (IMG:style_emoticons/default/wink.gif) Ale na Twoim etapie znajomości php tylko sobie za mocno byś skomplikował kod.
Go to the top of the page
+Quote Post
Zyx
post
Post #8





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Funkcje sprawdzające poprawność danych to dopiero początek, a nie powinny one niczego wyświetlać z prostego powodu: zaczniesz nowy projekt, skopiujesz kod i klops. Musisz przepisywać swoje funkcje, by je dopasować do nowej szaty graficznej, nowych wymagań i na pewno przy tym przepisywaniu zrobisz gdzieś błąd. Kod po to dzieli się na mniejsze, wyspecjalizowane w jednym zadaniu kawałki, by można ich było używać wielokrotnie w różnych sytuacjach.
Go to the top of the page
+Quote Post
andrzejt17
post
Post #9





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 24.06.2009
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Używam funkcji jsAlert() W argumencie podaje kod błędu a 2 drugim podaje nazwe pliku na który ma mnie przekierować po kliknięciu 'ok' przez użytkownika. Jeśli więc zwracam komunikat to zamiast tego echo co tam pisałem daje np jsAlert(100, 'index.php'); i jest git (IMG:style_emoticons/default/smile.gif) Jakoś nie czuje potrzeby napisania strony dla błędów, takie komunikaciki z powodzeniem mi wystarczają (IMG:style_emoticons/default/smile.gif)

Wezmę sobie do serca radę z funkcjami, że lepiej zrobić każdą funkcję do określonego zadania (IMG:style_emoticons/default/smile.gif)

Generalnie walidację formularza zrobię łącząc kawałek swojego sposobu i kawałek thek'a (IMG:style_emoticons/default/smile.gif)

Panowie, dziękuję za odpowiedzi.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 4.10.2025 - 21:50