Generowanie formularza na podstawie struktury tabeli MySQL

Dodano 29 MAR 2007 roku o godzinie 23:18:53

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;
 

Komentarze

#1

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

Albi | #

#2

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

radmen | #

#3

I tak to rozbuduje :P

Albi | #

#4

Spoko ;p

radmen | #

#5

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

doiy | #

#6

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

Albi | #

#7

SHOW COLUMNS FROM `$tabela`”

doiy | #

#8

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

radmen | #

#9

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.

Albi | #

#10

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

doiy | #

#11

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

Albi | #

#12

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

Albi | #

#13

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

doiy | #

#14

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

Albi | #

#15

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

doiy | #

#16

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ć

radmen | #

#17

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.

Michał Górny | #

#18

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

radmen | #

#19

Od razu lepiej ;D

Albi | #

#20

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?

radmen | #

#21

Popsułeś ^^

Albi | #

#22

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

radmen | #

#23

CTRL+F5?

Albi | #

#24

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

radmen | #

#25

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

Michał Górny | #

#26

A widzisz, dobrze wiedzieć :)

radmen | #

#27

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

goszczu | #

Disclaimer

Jakkolwiek jestem właścicielem tego bloga, nie ponoszę odpowiedzialności za kometarze napisane przez innych obywateli tego wolnego kraju.

Zastrzegam sobie prawo do kasowania/modyfikowania komentarzy (jeśli uznam to za stosowne).

Dodaj komentarz

code