Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [teoria] System pluginów do użytku przez usera
Forum PHP.pl > Forum > PHP
agmakonts
Wiem że jest wątek w dziale Pro o pluginach w aplikacjach ale dotyczy on innego typu wtyczek. Mi chodzi o ich wersje jaką znają zwykli szarzy użytkownicy którzy nie widza większej różnicy między BHP a PHP.

Aplikacja nie ma być żadnym cms-em który instalujemy na swoim serwerze tylko zwykłą aplikacją webową i tu pojawia się problem jak umożliwić użytkownikom rozszerzanie funkcjonalność bo wiadomo że nikt nie jest w stanie napisać programu który zaspokoi oczekiwania wszystkich dlatego system pluginów byłby mile widziany.
Takie rozwiązania niestety wymagają dodania do własnej aplikacji kodu osób trzecich a to do najbezpieczniejszych rzeczy nie należy.

Rozwiązanie znane np. z Facebooka jest genialne w swej prostocie ale sprawia (tak mi się wydaje) sporo problemów z przesyłaniem danych z serwera do tych aplikacji. Z resztą rozwiązanie z iframe nie podoba mi się do końca bo nie dość że zabija ograniczenia co do wyglądu to jeszcze cholera wie co się dzieje z danymi wyciągniętymi do aplikacji głównej na serwerach dodatku.

W moim przypadku pluginy nie mają być aż tak potężne by zmieniać całą aplikacje. Gdyby porównywać to do rozszerzeń w przeglądarkach to bliżej temu systemowi ma być do Chrome lub nawet widżetów w Operze niż mocnych, potrafiących zmienić całą przeglądarkę pluginów Firefoxa. Takie zwykłe małe programiki dodające np jedną ikonkę do paska narzędzi i pozwalające wyświetlić jakieś informacje lub obrobić istniejące, wypluć dane do innego formatu niż domyślne itp.

W teorii jest bardzo fajnie ale gdy doszedłem do momentu myślenia o implementacji zaczęły się problemy. Generalnie widzę dwie opcje jak to można zrobić:

Tworzenie:


Opcja 1 - Online:

Rozwiązanie dajce twórcom pluginów jakieś ładne IDE w serwisie gdzie mogą zrobić podstawowe GUI korzystając z danych im elementów (takie Visual Studio biggrin.gif) oraz dodawać funkcjonalność. O ile z tworzeniem samego GUI nie ma problemu bo przy zdefiniowanych elementach i nadawaniu im nazwy, etykiety itp działamy na zwykłym formularzu przyjmującym zwykły tekst i nie ma powodów do niepokoju o bezpieczeństwo. Problemy zaczynają się gdy trzeba kazać coś zrobić tym elementom interfejsu.
Wiadomo że udostępnienie pisania w czystym PHP lub JS jest niedopuszczalne i trzeba znaleźć alternatywę. Tutaj mocno zainspirowały mnie Smarty, pomyślałem że można by stworzyć taki własny pseudo język w obrębie PHP (więcej w części o języku;]). Takie rozwiązanie ma ten plus że kontroluje co twórca mi wysyła i mogę łatwo stworzyć bazę pluginów gdzie będą dodawane rozszerzenia po akceptacji. Dla użytkownika końcowego to też wygodne bo wchodzi sobie do tego mojego AppStore-a i wybiera co chce.
Takie rozwiązanie wydaje się też bezpieczniejsze bo żadnego dziwnego pliku nikt nie wrzuci na serwer. Jest ono jednak kłopotliwe dla twórców.

Opcja 2 - Offline:

W tym wariancie zakładam wysyłanie na serwer paczki np zip w której jest kilka plików. Definicja i opis pluginu w XML, schemat interfejsu też w XML i sam kod jeszcze nie wiem w czym smile.gif. Wysyłanie paczki jest o tyle wygodne że zawsze dostanę paczkę a nie np skrypt PHP a twórcy pozwala wygodnie rozbić warstwy. To rozwiązanie jest jednak o wiele mniej bezpieczne i utrudnia robienie bazy pluginów z której mogli by korzystać użytkownicy. Podobnie jak przypadku wersji Online musiałby powstać jeżyk tych rozszerzeń. Trudną sprawą jest tutaj testowanie pluginu bo jak udostępnić API serwujące choćby testowe dane by nie mijało się to z celem trzymania pluginów u siebie i było wygodne, na razie nie wiem.

Pseudo opcja dla chętnych i posiadających za wiele czasu oraz mało znajomych 3 - Hybryda

Połączyć obydwa rozwiązania.

Język:

Tutaj zaczęły się moje największe problemy, jak pozwolić komuś na odpalenia własnego kodu na moim serwerze, w obrębie mojej aplikacji i byłoby to na tyle bezpieczne bym nie został nazwany szaleńcem. Tak jak pisałem zainspirowały mnie Smarty i ich własny języczek używany w szablonach, jakby nie było komenda w stylu {loop &data}{/loop} nie może zbytniej szkody wyrządzić. Wiadomo że do napisania prostych pluginów nie potrzeba obiektów, super wyrafinowanych typów zmiennych, połączeń z bazą danych i innych bajerów. Implementacja najprostszych poleceń nie powinna być trudna, to jak tan język będzie wyglądać jest jeszcze do przemyślana. Miałem małą styczność z vb.net i pomyślałem że można by tutaj przeszczepić bardzo okrojoną wersję obsługi zdarzeń. Chodzi o to że jeśli mamy w interfejsie pole tekstowe o nazwie "text1" i obok przycisk "napisz Hello World" o nazwie "button1" to nasz kod mógłby wyglądać tak:

Kod
[GUI button1 "button1" [clickLive]]
     text1.text = "Hello World";
[/GUI button1]


Takie coś generowałoby np taki JS:

Kod
    $('#plugin_name_button1').click(function(){$('#plugin_name_text1').val('Hello World')});


Jest to szalenie prosty przykład, wiadomo że trzeba będzie wyjść też poza przeglądarkę i czasem stworzyć kod PHP i umożliwiać jakieś bardziej skomplikowane operacje ale myślę że mając podstawy nie będzie trudno to zrobić.

Kolejny problem to filtrowanie, zabezpieczenie się przed wgraniem <php die(); ?> nie jest trudne ale jeśli udostępnię funkcję do obsługi ciągów to 'bbb<bbb?bbbpbbbhbbbpbbb-bbbdbbbibbbebbb(bbb)bbb;bbb-bbb?bbb>' może być niebezpieczne przy {replace $string | 'bbb' -> '' | '-' -> ' '}.

Pytania:

Co o tym sądzicie? Czy nie jest to rzucanie się z motyką na słońce? Może jest lepszy sposób na stworzenie tego systemu? O czym jeszcze nie pomyślałem?

marcio
Cytat
W moim przypadku pluginy nie mają być aż tak potężne by zmieniać całą aplikacje. Gdyby porównywać to do rozszerzeń w przeglądarkach to bliżej temu systemowi ma być do Chrome lub nawet widżetów w Operze niż mocnych, potrafiących zmienić całą przeglądarkę pluginów Firefoxa. Takie zwykłe małe programiki dodające np jedną ikonkę do paska narzędzi i pozwalające wyświetlić jakieś informacje lub obrobić istniejące, wypluć dane do innego formatu niż domyślne itp.

Polecam 3 rozmawiazania kazde potrafi rozwiazac twoj problem na 3 rozne sposoby, zamiast zabawy w jakies wlasne jezyki i systemy zdarzen....

Po pierwsze filtry:
Masz glowna akcje kontrolera jakiegos modulu, sprawdzasz czy istnieje filtr dla danego kontrolera i dla wykonywanej akcji...przechwycasz wygenerowana tresc z kontrolera w filtrze i z kodem mozesz robic co ci sie zywnie podoba...

Widget'y:
Z tego co rozumiem chcesz proste "moduly" ktore nie potrzebuja ani pobierac danych ani ich zapisywac, lecz "upiekszac" wyglad strony...
Wiec masz glowny Widok/Szablon aplikacji a w nim zostawiasz miejsca na wstrzykiwane widget'ow np tak:
  1. //view menu.php
  2. //masz linki i chcesz zeby mozna bylo pod nimi dodac jaki bajer....wiec robisz...
  3. <a></as>
  4. <a></as>
  5. <a></as>
  6. <a></as>
  7. <?php echo $widget['menu']; ?>

W glownym kontrolerze ladujesz widget'y kiedy i gdzie chcesz, a widget sklada sie z wlasnego kontrolera i widoku, lub jesli potrzebujesz wieksza funkcjonalnosc to robisz to za pomoca pluginow dodac tylko Model do kazdego z nich ale sama idea dzialania jest taka sama...

Hooki/Eventy:
Robisz prosty system hook'ow, potem pod odpowiedni hook podczepiasz odpowiednia akcje...
  1. <?php
  2.  
  3.  
  4. class Hooks {
  5.  
  6. private static $hooks = array();
  7.  
  8. private static $runs = array();
  9.  
  10. public static $data;
  11.  
  12. public static function getHooks($event) {
  13.  
  14. return (!empty(self::$hooks[$event])) ? self::$hooks[$event] : array();
  15.  
  16. }
  17.  
  18.  
  19. public static function AddHook($event, $hook) {
  20.  
  21. if(!isset(self::$hooks[$event])) {
  22.  
  23. self::$hooks[$event] = array();
  24.  
  25. }
  26.  
  27. else if(in_array($hook, self::$hooks[$event])) {
  28.  
  29. return false;
  30.  
  31. }
  32.  
  33. self::$hooks[$event][] = $hook;
  34. return true;
  35.  
  36. }
  37.  
  38.  
  39. public static function RunHook($event, $data = null) {
  40.  
  41. if(!empty(self::$hooks[$event])) {
  42.  
  43. self::$data = $data;
  44.  
  45. foreach(self::$hooks[$event] as $evt) {
  46.  
  47. $hook = explode('.', $evt);
  48. $className = $hook[0];
  49. $methodName = $hook[1];
  50. self::$data .= call_user_func(array($className, $methodName));
  51. self::$runs[$event] = $event;
  52.  
  53.  
  54. }
  55.  
  56. }
  57.  
  58. }
  59.  
  60.  
  61. public static function HasRunHook($event) {
  62.  
  63. return isset(self::$runs[$event]);
  64.  
  65. }
  66.  
  67. }
  68.  
  69.  
  70.  
  71. ?>


Ja tak to widze....
agmakonts
Rozbicie tego na filtry i widżety jest fajnym pomysłem, muszę nad tym jeszcze pomyśleć dogłębniej. Nie wiem tylko czy się dobrze zrozumieliśmy, czytałem sporo o systemach pluginów, między innymi tu na forum ale mimo zastosowania dobrych i sprawdzonych rozwiązań nadal pozostaje kwestia oddania mocy twórczej każemy na świecie. Chodziło mi o to że mam aplikacje na swoim serwerze, jest ona publicznie dostępna, każdy sobie może założyć konto itp a plugin może napisać każdy i odpalić każdy. I to moim zdaniem wymaga własnego języka i systemu zdarzeń bo nie mogę pozwolić wygrywać czystego JS lub PHP na mój serwer i jeszcze pozwolić wykonywać te skrypty.

Co do samego zaplecza, system hook/event który pokazałeś wygląda bardzo przyjemnie, dzięki za wskazówkę smile.gif

Nie chcę Cię posądzać o złe zrozumienie mojego posta bo sam nie wiem czy dobrze rozumiem Twój:) Nie chodzi mi o system pluginów jaki jest np w Wordpressie czy innym CMSie który instalujesz na swoim serwerze i jak go rozwalisz to Twój problem, chodzi mi o rozwiązanie gdzie porównując znów do Wordpressa byłaby możliwość pisania pluginów do blogów na Wordpress.com.

Ponownie rozważyłem pluginy na iframe i hostowane na serwerach zewnętrznych jak jest z aplikacjami na FB tylko z kolei tutaj pojawia się problem z filtrowaniem i kontrolą zawartości. Chcę by wszystkie dodatki korzystały z tych samych elementów interfejsu, były spójne a co najważniejsze nie robiły z danymi co im się podoba, dzięki pluginom na własnym serwerze jestem w stanie zabezpieczyć użytkowników przed złośliwymi dodatkami.

marcio
Nie dawaj mozliwosci tworzenia widget'ow wszystkim, kod to bedzie kiszka, jedna wielka porazka, juz nie mowiac o wydajnosci itp..itd...

Jak juz chcesz zrobic cos elastycznego to maximum daj uzytkownikowi mozliwosc modyfikacji widoku widget'u i tyle ale sama funkcjonalnosc to ty napisz...

W ogole nie rozumiem po co chcesz takie cos osiagnac...?Jakies nietypowe rozwiazanie....moze napisz co probujesz zrealizowac dokladnie, dlaczego uzytkownicy moga pisac wlasne "rozszerzenia"?

A jak nie zrob spojne API dla "rozszerzen" i pliki ini/xml do konfiguracji wtyczki, po czym zrob akceptacje wtyczki przez admina zeby mozna bylo ja uzywac, sprawdzisz czy wtyczka jest bezpieczna i tyle.
agmakonts
Ma to być część systemu zarządzania projektami/zleceniami przy którym obecnie pracuje, wymogi są takie że ma być opcja rozszerzania tego, chodzi o utworzenie jakieś społeczności i zwiększanie popularności przez możliwości ekstremalnego dostosowania.

System ma być zwykłym menadżerem a przykładowy plugin to np automatyczny przelicznik walut przy wynagrodzeniu lub mały organizer spotkań z klientami który od razu sprawdzi Ci połączenie lotnicze.

Co do samego api i konfiguracji np w xml to jak najbardziej, tylko właśnie... api jak to najlepiej zrobić by było bezpiecznie i wygodnie dla wszystkich skoro mówisz że własny system znaczników/język jest złym pomysłem. Akceptacja przez admina też jak najbardziej (przy bazie dodatków o której mówiłem jest to konieczne).

Wiem że pomysł jest ekstremalny i najlepszym możliwym sposobem zrobienia tego jest nie robienie w ogóle ale mus to mus.

Co do wydajności.... myślę że jeśli api będzie ograniczało możliwości do minimum to nawet najgorsze jego wykorzystanie nie będzie tragicznie jechać po wydajności a zawsze można odesłać gościa z kwitkiem by poprawił to i owo.
marcio
Cytat
Co do samego api i konfiguracji np w xml to jak najbardziej, tylko właśnie... api jak to najlepiej zrobić by było bezpiecznie i wygodnie dla wszystkich skoro mówisz że własny system znaczników/język jest złym pomysłem. Akceptacja przez admina też jak najbardziej (przy bazie dodatków o której mówiłem jest to konieczne).

Zrob interfejs IPlugin dla kazdego plugin'u z metodami:
  1. interface IPlugin {
  2.  
  3. public function install();
  4. public function unistall();
  5. public function CheckVersion();
  6. public function activate();
  7. public function deactivate();
  8.  
  9. }

Zrob klase bazowa dla kazdego plugin'u/wtyczki czy jak to chcemy nazwac winksmiley.jpg
W tej klase daj dostep tylko do niektorych obiektow, do tych ktore pluginy moga miec dostep np: User,View,Validation,Auth/Acl,FormBuilder, jesli potrzebujesz tez modelu to rozbij kazdy plugin na mvc klasa bazowa dla kontrolera a kazdy model bedzie dziedziczyl po twojej klasie glownego modelu aplikacji...

Potem gdy masz wtyczke:
  1. class ForeignExchange extends Plugin implements IPlugin { }

I teraz tak jesli metody install/unistall maja tworzyc tabele w bazie danych i "instalowac" pliki pluginu zrob to za pomoca interfejsu jesli maja tylko instalowac pliki mozesz zrobic w klasie Plugin metody abstrakcyjne CheckVersion/Activate/Deactivate a metody install/unistall zrobic takie same dla kazdego pluginy, jesli jednak maja one tworzyc strukture pluginu w bazie to uzyj interfejsy wtedy kazdy plugin bedzie mogl sie instalowac na "swoj sposob"
Do tego dodaj akceptacje przez admina i tyle...

Nie wiem czy ci pomoglem tym postem...mam nadzieje ze tak winksmiley.jpg
Crozin
Dlaczego niby miałbyś nie pisać tego? Z tego co widzę ma to być coś na kształt aplikacji znanych z Facebooka. Sam na ich działaniem od strony owego Facebooka się nigdy specjalnie nie zastanawiałem (mimo iż nawet jedną aplikację na niego napisałem), ale Ty powinieneś rozważyć opcję popodglądania ich.

1. Udostępnij system autoryzacji - każdy użytkownik przy instalacji takiego rozszerzenia powinien mieć pełną wiedzę na tym z jakich danych chce korzystać dany plugin. I plugin ten powinien mieć dostęp wyłącznie do tych danych.
2. Przed "złymi" się nie obronisz, bo i zwykła pętla potrafi narobić spory problem:
[JAVASCRIPT] pobierz, plaintext
  1. for (var i = 0; i < 1e10; i++) { /* zrób coś */ }
[JAVASCRIPT] pobierz, plaintext
Musisz po prostu monitorować jakie pluginy się pojawiają.
3. Do tworzenia GUI wykorzystaj XML, bo nadaje się do tego idealnie (a dokładniej jego fajna cecha zwana przestrzeniami nazw).
  1. <p>Witaj świecie <myApp:button>Kliknij tutaj</myApp:button> by uzyskać więcej informacji.</p>

4. Wrzucenie wszystkiego do ramki nie jest złym pomysłem, bo utrudnia zdobycie danych przy pomocy JS (nie można np. odczytać z kodu strony nadrzędnej informacji z drzewa DOM). Trzymanie pluginów na zew. serwerach powoduje, że nikomu nie uda się wykonać jakiegoś paskudnego kodu na Twoim serwerze.
5. Stosując się do punktu czwartego możesz też bardzo łatwo kontrolować ile danych otrzyma jaki plugin (patrz pkt. 1), bo wszystkie te dane będą płynąć z serwera po uprzedniej autoryzacji pluginu.
6. Nie zapomnij udostępnić czegoś w stylu bazy danych dla pluginów - nie ukrywajmy... one muszą zachowywać całą masę danych.
agmakonts
Rozwiązanie facebookowe bardzo mnie kusi cały czas, sporo czasu spędziłem z nosem w ich dokumentacji.

Xml do gui to jak dla mnie jedyna opcja tylko właśnie, jak zmusić programistów by wysyłali tylko xml do ramki, nawet gdy będzie ładnie przy autoryzacji to zmienić zawartość skryptu który wyświetla ramka potem nie jest trudno.

Przed chwilą myślałem nad jeszcze jedną opcją, całość oprzeć na xml, nie tylko gui ale i funkcjonalność i hostowac to u siebie.
To oczywiście przykład ale myślę że jest dosyć czytelny. Nadal nie zdecydowałem się na żadne rozwiązanie ale to chyba może pretendować do tutułu "mającego szanse"

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <plugin container="toolbar" position="default">
  3. <name>Zista zadan</name>
  4. <type>widget</type>
  5. <button>
  6. <icon>icon.png</icon>
  7. <text>Zista zadan</text>
  8. <tooltip>Dodaj zadanie</tooltip>
  9. <action show="main"/>
  10. </button>
  11. <widget>
  12. <dataBase>
  13. <field>title</field>
  14. <field>detail</field>
  15. </dataBase>
  16. <canvas name="main">
  17. <title>Dodaj zadanie</title>
  18. <interface>
  19. <label>Dodaj do listy zadan:</label>
  20. <container name="info"></container>
  21. <textbox name="taskTitle"/>
  22. <textbox name="taskDetail"/>
  23. <button name="submit" ation="addTask">Dodaj</button>
  24. <link show="showTasks">Pokaż liste zadan</link>
  25. </interface>
  26.  
  27. <action name="addTask">
  28. <dataBase>
  29. <add>
  30. <record>
  31. <name>task</name>
  32. <field name="title"><parameter valueFrom="taskTitle"/></field>
  33. <field name="detail"><parameter valueFrom="taskDetail"/></field>
  34. </record>
  35. <return targer="info">
  36. <success>Dodano pomyślnie</success>
  37. <error>Wystąpił błąd</error>
  38. </return>
  39. </add>
  40. </dataBase>
  41. </action>
  42. </canvas>
  43.  
  44. <canvas name="showTasks">
  45. <title>Lista zadan</title>
  46. <interface>
  47. <dbLoop fromDb="taks | limit:10">
  48. <label><field name="title"/></label>
  49. <label><field name="detail"/></label>
  50. </dbLoop>
  51. </interface>
  52. </canvas>
  53. </widget>
  54. </plugin>
  55.  



W trakcie pisania tego posta wpadłem an rozwiązanie chyba rozwiązujące mój problem. Autoryzacja pluginu tak jak mówiłeś a potem zapytanie przez cURL, wysyłanie żądanych danych przez POST i wpakowanie tego do diva. To da mi możliwość sprawdzenia jakimś regexem czy wszystko jest jak ma być. Co o tym sądzicie?
Crozin
Popatrz jak to jest już rozbudowane. Będziesz musiał przewidzieć nie dziesiątki, a setki takich elementów, a i tak będzie to interfejs pozwalający jedynie na prostsze operacje. O tym jak rozbudowana będzie musiała być jego dokumentacja, ile pracy włożysz w napisanie programu potrafiącego zamienić takie coś na "normalny kod" czy jak niewygodne będzie pisanie tego już nie chcę pisać nawet. Co najgorsze - będzie to cholernie nieelastyczne.

Myślę, że niepotrzebnie próbujesz stworzyć autorskie rozwiązanie, problemu który już został całkiem dobrze rozwiązany (patrz: nieszczęsny facebook).
agmakonts
Też powoli do takiego wniosku dochodzę, a co sądzisz o tym co pisałem na koncu? By korzystać z zewnętrznych serwerów jak na FB ale lądować to przez cURLa?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.