Generowanie formularza na podstawie struktury tabeli MySQL

Raz na stronie zlecenia.przez.net znalazłem zlecenie dotyczące stworzenia skryptu, który generuje formularz na podstawie struktury tabeli MySQL. Pomyślałem sobie, że to zadanie jest czymś ciekawym dla mnie i w wolnej chwili postanowiłem napisać prosty (a właściwie prowizoryczny) skrypt, który by wykonywał takie zadanie.


Teoria

Na początku szukałem przeróżnych funkcji do obsługi MySQL, które oferuje PHP. Coś tam niby znalazłem, ale one były dla mnie niewystarczające. Po prostu nie spełniały moich wymagań.
Gdzieś w komentarzach na stronie php.net natknąłem się na pewien ciekawy komentarz.

Właściwie bezsensem było szukanie skomplikowanych funkcji. Kluczem do eksportu struktury dla jakiejś tabeli było zapytanie SQL: “SHOW COLUMNS FROM `tabela`”.

Wynik tego zapytania zwróci nam (np) coś takiego:

mysql> show columns from `lol`;
+----------+------------------------------------------------+------+-----+---------+-------+
| Field    | Type                                           | Null | Key | Default | Extra |
+----------+------------------------------------------------+------+-----+---------+-------+
| test     | enum('zlo','dobro','papa smerf','nerd','blah') | NO   |     |         |       |
| text     | varchar(100)                                   | NO   |     |         |       |
| textarea | text                                           | NO   |     |         |       |
+----------+------------------------------------------------+------+-----+---------+-------+
3 rows in set (0.04 sec)

Jak widać wynik tego zapytania może być wystarczający do tego aby wygenerować formularz. Także przejdźmy już do jakiś konkretów…

Praktyka

Ok to oczywiście standardowo połączenie z bazą danych, oraz natychmiastowe wykonanie zapytania do bazy MySQL.

define("MYSQL_USER", "user");
define("MYQL_PASS", "pass");
define("MYSQL_HOST", "localhost");
define("MYSQL_BASE", "lol"); // przykladowa nazwa bazy ;p

$tabela ="lol"; // tabela na podstawie której powstanie formularz
$form = array(); // stworzenie tablicy form, która będzie trzymała dane potrzebne to stworzenia formularza

mysql_connect(MYSQL_HOST, MYSQL_USER, MYQL_PASS) or die ("Nie mozna polaczyc sie z baza MySQL!");
mysql_select_db(MYSQL_BASE) or die ("Nie mozna wybrac bazy danych!");

$result = mysql_query("SHOW COLUMNS FROM `$tabela`");

Ok, to skoro połączenie już mamy to teraz czas na fetch’owanie ;-)

while($row = mysql_fetch_object($result))
{
//     (...)
}

Póki co ta pętla jest pusta. Stało się tak dlatego, że chcę z osobna opisać co się będzie działo.

W tej pętli nastąpi “analiza” wyników. Zostanie pobrana nazwa pola, oraz jego typ i default’owa wartość. Wszystkie te informacje zostaną zapisane do tablicy $form, która posłuży później do generowania formluarza.

Jak pisałem wcześniej ten skrypt będzie prosty, także nie liczcie na to, że obsłuży każdy typ pola ;-)

Generalnie sprawa będzie wyglądała tak:

  • $row->Type = “varchar” lub “char” => input type=text
  • $row->Type = “enum” lub “set” => input type=radio
  • $row->Type = “text” => pole textarea

Jedynym problemem, może być wyciągnięcie wartości z pól “enum” lub “set”, bo jak wiadomo są one ustawione “z góry” (właśnie dlatego wstawi się do formularza pole radio). Wprawdzie zamiast pola radio można posłużyć się <select> z tylko jedną możliwością wyboru, ale myślę, że przedstawione przeze mnie rozwiązanie nie sprawi większych problemów.

Ok, to najpierw pokażę kod, a potem postaram się go objaśnić.

if(preg_match("/(enum|set)/", $row-&gt;Type))
{
        $options=explode("','", preg_replace("/(enum|set)\('(.+?)'\)/","\\2", $row-&gt;Type));
        $form[$row-&gt;Field] = array("type" =&gt; "radio", "value" =&gt; $options);
}

Nie wygląda tak źle, prawda? Instrukcja warunkowa jest jasna. Zmylić może wartość zmiennej $options.
Normalnie zmienna $row->Type dla pola “enum” (lub “set”) wygląda tak: enum(‘val1′,’val2′).

Funkcja explode “rozrywa” wszystkie stringi, które są podzielone znakiem przecinka (“,”), ale zanim to nastąpi funkcja preg_replace usunie zbędne fragmenty, czyli “enum(” i “)” ;-)

Zakończenie

Wygenerowanie formularza już nie powinno sprawić większych problemów. Na wszelki wypadek na końcu tej notki umieszczę jeszcze cały kod tego skryptu (wraz z wygenerowanym formularzem).
Ten skrypt nie jest doskonały, można dużo zmienić i poprawiać. Nie pokażę kodu zapisującego dane z formularza, bo myślę, że dacie sobie radę (gdyby jednak tak nie było to mogę potem coś o tym naskrobać) ;-)

Teraz mała uwaga do “znawców”. Jeśli jesteście zdania, że można to zrobić lepiej, to proszę bardzo róbcie, ale nie krytykujcie mnie za to, że zrobiłem to inaczej. Oczywiście wszelkie rady chętnie przyjmę, a błedy poprawię :)

Kodziwo

&lt;?php
// Generator formularza na podstawie struktury bazy MySQL
// Made by radmen
// radmen [at] gmail dot com
// Copyleft
//

define("MYSQL_USER", "root");
define("MYQL_PASS", "mysql-pass");
define("MYSQL_HOST", "localhost");
define("MYSQL_BASE", "lol");

$tabela = "lol"; // tabela na podstawie której powstanie formularz
$form = array(); // stworzenie tablicy form, która będzie trzymała dane potrzebne to stworzenia formularza

mysql_connect(MYSQL_HOST, MYSQL_USER, MYQL_PASS) or die ("Nie mozna polaczyc sie z baza MySQL!");
mysql_select_db(MYSQL_BASE) or die ("Nie mozna wybrac bazy danych!");

$result = mysql_query("SHOW COLUMNS FROM `$tabela`");
while($row = mysql_fetch_object($result))
{
        // $row-&gt;Field =&gt; nazwa rekordu
        // $row-&gt;Type =&gt; typ rekordu
        
        if(preg_match("/(enum|set)/", $row-&gt;Type))
        {
                $options=explode("','", preg_replace("/(enum|set)\('(.+?)'\)/","\\2", $row-&gt;Type));
                $form[$row-&gt;Field] = array("type" =&gt; "radio", "value" =&gt; $options);
        }
        if(preg_match("/(varchar|char)/", $row-&gt;Type))
        {
                $form[$row-&gt;Field] = array("type" =&gt; "text", "value" =&gt; $row-&gt;Default);
        }
        if(preg_match("/text/", $row-&gt;Type))
        {
                $form[$row-&gt;Field] = array("type" =&gt; "textarea", "value" =&gt; $row-&gt;Default);
        }
}

// Formularz - tutaj wyjątkowo prymitywny ;p

echo "&lt;form&gt;\n";
foreach ($form as $name =&gt; $info)
{
        if($info['type'] == "text")
        {
                echo "&lt;p&gt;$name: &lt;input type=\"text\" name=\"$name\" value=\"".$info['value']."\"/&gt;&lt;/p&gt;\n";
        }
        
        if($info['type'] == "textarea")
        {
                echo "&lt;p&gt;$name &lt;textarea name=\"$name\"&gt;".$info['value']."&lt;/textarea&gt;&lt;/p&gt;\n";
        }
        
        if($info['type'] == "radio")
        {
                echo "&lt;p&gt;$name: ";
                foreach ($info['value'] as $RadioValue)
                {
                        echo "$RadioValue &lt;input type=\"radio\" name=\"$name\" value=\"$RadioValue\"&gt; ";
                }
                echo "&lt;/p&gt;\n";
        }
}
echo "&lt;/form&gt;";
?&gt;

29 Responses to “Generowanie formularza na podstawie struktury tabeli MySQL”

  1. Albi March 29, 2007 at 11:18 pm #

    Heh, miałem sam coś takiego napisać :> Ułatwiasz życiom ludzie ;)
    Teraz tylko automatyczna edycja pól i zapisywanie/kasowanie rekordów. THX :>

  2. radmen March 29, 2007 at 11:18 pm #

    Hehehe cieszę się, że pomogłem ;p

  3. Albi March 29, 2007 at 11:18 pm #

    I tak to rozbuduje :P

  4. radmen March 29, 2007 at 11:18 pm #

    Spoko ;p

  5. doiy March 29, 2007 at 11:18 pm #

    Czy tym prostym zapytaniem nie wystawiłeś bazy na SQL Injection(jeśli by pobierać potem $tabela z POST/GET)? :D

  6. Albi March 29, 2007 at 11:18 pm #

    Nie możliwe, w zapytaniach SQL nie ma żadnej zmiennej… =.=

  7. doiy March 29, 2007 at 11:18 pm #

    SHOW COLUMNS FROM `$tabela`”

  8. radmen March 29, 2007 at 11:18 pm #

    doiy: to jest tylko totalny przykład ;-)
    Aczkolwiek masz rację i zaraz to poprawię :p

  9. Albi March 29, 2007 at 11:18 pm #

    Dobra, jestem ślepy… To przez kolorowanie składni, nigdy nie używam „ ;) Mimo to $tabela nie jest superglobalna, chyba że register_globals=On. Wtedy i tak wszystko jest nadpisywane, a sam skrypt jest czysto teoretyczny przecież :> Z drugiej strony ktoś nieostrożny (czyt. noobek :>) mógłby popełnić taki błąd.

  10. doiy March 29, 2007 at 11:18 pm #

    Ja wiem, ale po co przyzwyczajać ludzi? ;)

  11. Albi March 29, 2007 at 11:18 pm #

    Kurde, jaki to ma sens, bo nie rozumiem? :| „$tabela = mysql_escape_string(„lol”);” Eskejpujesz stringa zapisanego na sztywno w skrypcie? ^^

  12. Albi March 29, 2007 at 11:18 pm #

    Argh, edycji nadal nie ma :D
    Funkcja nazywa sie mysql_real_escape_string();

  13. doiy March 29, 2007 at 11:18 pm #

    Tak właśnie patrzałem podejrzliwie na to, ale przecież na PHP się nie znam :)

  14. Albi March 29, 2007 at 11:18 pm #

    W dzisiejszych czasach cięzko powiedzieć, że się na czymś zna, bo zawsze znajdzie się ktoś lepszy ;) I’m just learning lame :>

  15. doiy March 29, 2007 at 11:18 pm #

    No tak, ale PHP nigdy nie ruszałem głębiej. Jeden skrypt napisałem sam. Reszta to modyfikacje for/cms.

  16. radmen March 29, 2007 at 11:18 pm #

    Albi: najpierw się czepiałeś, że niby będzie SQL ijection, a teraz po małej modyfikacji czepiasz się, że i tak go nie ma :P

    Przywrócę wersję do oryginału, a Wy sami sobie to modyfikujcie ;p

    Co do edycji komentarza, cały czas nie chce mi się tego zrobić, postaram się to dzisiaj wieczorem wykonać

  17. Michał Górny March 29, 2007 at 11:18 pm #

    Ech, tyle roboty… a w Perlu to mamy praktycznie w komplecie — generowanie formularzy, walidowanie ich (per JS i CGI), zwracanie błędów — po prostu CGI::FormBuilder.

  18. radmen March 29, 2007 at 11:18 pm #

    Albi: już masz możliwość edytowania komentarzy ;p

  19. Albi March 29, 2007 at 11:18 pm #

    Od razu lepiej ;D

  20. radmen March 29, 2007 at 11:18 pm #

    Hmm to jest ciekawe… W tym wpisie mogę edytować własne komentarze, a w poprzednich już w ogóle nie pokazuje tego linka :/

    Co może być nie tak?

  21. Albi March 29, 2007 at 11:18 pm #

    Popsułeś ^^

  22. radmen March 29, 2007 at 11:18 pm #

    Ale co? Przeca szablon dla komentarzy jest taki sam, także co jest grane ?

  23. Albi March 29, 2007 at 11:18 pm #

    CTRL+F5?

  24. radmen March 29, 2007 at 11:18 pm #

    Nie to nie pomaga… Tylko w tej notce mogę edytować własne komentarze.. Dziwy, dziwota o0

  25. Michał Górny March 29, 2007 at 11:18 pm #

    …bo komentarze można chyba tak tylko przez jakiś czas edytować.

  26. radmen March 29, 2007 at 11:18 pm #

    A widzisz, dobrze wiedzieć :)

  27. goszczu March 29, 2007 at 11:18 pm #

    fajne, coś prostego co można w kwadrans rozgryźć i samemu rozwinąć wg upodobania

  28. tomekpl March 29, 2007 at 11:18 pm #

    Wszedłem na twojego bloga, sam nawet już nie pamiętam jak, jakąś godzinę temu i muszę przyznać, że z twoim podejściem do różnych spraw miło i chętnie się czyta :)

    Pzdr

  29. iar March 29, 2007 at 11:18 pm #

    Jak by na to nie patrzeć sam kod jest ok i pewnie pomógł wielu ludziom przecież to nazwijm baza do rozbudowy i jest ok ale ja kombinuje coś takiego żeby mieć formularz zamówienia z arkuszem kalkulacyjnym ma ktoś pojęcie o tym ?