Udviklingen af ​​WordPress fra en bloggingplatform til et fuldt udbygget CMS, gør det samtidig til en solid ramme for udviklere til at opbygge fremragende projekter og applikationer på.

WordPress-kernen giver ikke blot brugerne udgivelsesmotor, men giver også udviklere et robust sæt af klasser, API'er og hjælpere, der er designet til at imødekomme en bred vifte af behov.

En af skjulte perler af WordPress, som giver udviklere mulighed for at udføre operationer med det lokale filsystem på en sikker og robust måde, er WordPress Filesystem API. Den abstraherer filmanipuleringsfunktionalitet til et sæt almindeligt ønskede metoder, så de kan bruges sikkert i forskellige hosting-miljøer.

Omfanget af problemet

Der kan være flere grunde til at have lyst til at skrive lokale filer i kode:

  • Logning af begivenheder eller udførte operationer
  • Dataudveksling med ikke-WordPress-drevne systemer
  • Backup

Uanset motivationen kan det være en risikabel handling at skrive lokale filer fra PHP-kode. Mindst to meget vigtige faldgruber skal tages i betragtning ved implementering af dette til et WordPress-tema, plugin eller brugerdefineret installation:

  1. Sikkerhed. Der er risiko for forkert fil ejerskab, når der skrives lokale filer med kode (af webserveren). Dette problem opstår i dårligt konfigurerede shared hosting-miljøer og kan føre til tab af kontrol over filer.
  2. Kompatibilitet. På grund af de mange hostingfirmaer derude, er den specifikke brugers serverkonfiguration normalt ukendt for bygherren. Udvikleren kan således ikke være sikker på, at tilladelser, der kræves til en skriveoperation, kan opnås af brugeren af ​​plugin eller tema.

Hvis en WordPress-plugin eller et tema, der skal skrive lokale filer, er beregnet til offentlig udgivelse, skal udvikleren konstant bære disse problemer i tankerne. Den gode nyhed er, at WordPress selv allerede har et værktøj til at løse disse problemer: Filesystem API.

Introduktion til WordPress Filesystem API

Filsystemet API blev tilføjet til WordPress i version 2.6 for at aktivere WordPress 'egen opdateringsfunktion. Den abstraherer den nødvendige funktionalitet til at udføre læse / skrive operationer sikkert og på en række værtsformer. Den består af et sæt klasser og giver dig mulighed for automatisk at vælge den rigtige måde at oprette forbindelse til det lokale filsystem på, afhængigt af individuel værtopsætning.

Logikken bag API'en er ganske enkel; det forsøger at skrive lokale filer direkte, og i tilfælde af forkert fil ejerskab skifter det til en anden FTP-baseret metode. Afhængigt af de tilgængelige PHP-biblioteker finder den en passende måde at opsætte en FTP-forbindelse (via udvidelsesstik eller over-SSH). Generelt kræves følgende trin for at arbejde med lokale filer:

Trin 1. Find hvilken forbindelsesmetode der er tilgængelig

WordPress bruger get_filesystem_method til at registrere tilgængeligheden af ​​følgende metoder (fra højeste prioritet til laveste) Direkte, SSH2, FTP PHP Extension, FTP Sockets.

Trin 2. Hent de legitimationsoplysninger, der kræves for den registrerede metode

Hvis den registrerede transport har brug for legitimationsoplysninger fra en bruger, bruger WordPress funktionen request_filesystem_credentials til at vise en anmodningsformular. Funktionen har en række parametre, der gør det muligt at bevare data mellem formularindlæg, bede om legitimationsoplysninger flere gange, hvis forbindelsen mislykkedes, og målrette mod en bestemt mappe inde i WordPress-installationen:

request_filesystem_credentials($form_post, $type, $error, $context, $extra_fields);

Ved at levere en tom $ type parameter til funktionen kunne vi tvinge den til at udføre detektion af de tilgængelige forbindelsesmetoder, så det ville kalde get_filesystem_method for os. Samtidig kan vi tvinge funktionen til at bruge en bestemt forbindelsestype ved at angive den ved hjælp af argumentet $ type.

Når de forbindelsesdata, der kræves af den valgte metode, ikke er angivet, udskriver funktionen formularen for at anmode om den:

Conneciton information

Efter den første anmodning gemmer WordPress FTP værtsnavnet og brugernavnet i databasen til fremtidig brug, men det lagrer ikke adgangskoden. Alternativt kan FTP-legitimationsoplysninger angives i wp-config.php-filen ved at bruge følgende konstanter:

  • FTP_HOST - værtsnavnet på serveren til at oprette forbindelse til
  • FTP_USER - brugernavnet til at oprette forbindelse til
  • FTP_PASS - adgangskoden til at forbinde med
  • FTP_PUBKEY - stien til den offentlige nøgle til brug for SSH2-forbindelse
  • FTP_PRIKEY - stien til den private nøgle til brug for SSH2-forbindelse

Når disse data er gemt i wp-config.php filen, vises forespørgselsformularen ikke, men sikkerhedsfejlene er signifikante, og sikkerhedsprocedurerne skal triple-kontrolleres med den højeste opmærksomhed, der er muligt, bør betales til sikkerheden for denne fil.

Trin 3. Initialiser WordPress Filesystem-klassen og opret forbindelse til filsystemet

Hjertet af WordPress Filesystem API er WP_Filesystem-funktionen. Den indlæser og initialiserer den relevante transportklasse, gemmer et opnået eksempel i det globale $ wp_filesystem objekt til yderligere brug og forsøger at forbinde filsystemet med de medfølgende referencer:

WP_Filesystem($args, $context);

Trin 4. Brug WordPress Filesystem metoder til at udføre læs / skrive operationer

Et korrekt initialiseret $ wp_filesystem objekt har et sæt metoder til at kommunikere med det lokale filsystem, som kunne bruges uden yderligere angst for forbindelsestype. Især er der følgende almindeligt anvendte metoder:

  • get_contents - læser filen i en streng
  • put_contents - skriver en streng til en fil
  • mkdir - opretter en mappe
  • mdir - fjerner en mappe
  • wp_content_dir - returnerer stien på det lokale filsystem til mappen wp-indhold
  • wp_plugins_dir - returnerer stien på det lokale filsystem til plugins mappen
  • wp_themes_dir - returnerer stien på det lokale filsystem til tememappen

Hvis vi laver det hele sammen, lad os komme med et eksempel, der udfører ovenstående trin i en simpel situation - vi vil skrive en tekst, der indsendes i en tekstarea, til en almindelig .txt-fil.

Bemærk, at dette eksempel er til demonstrationsformål. I en situation i virkeligheden ville du ikke gemme enkle tekstdata i en .txt-fil, det ville være en langt mere robust løsning til at gemme den i databasen i stedet.

WordPress Filesystem API i aktion

Lad os pakke vores kode i et separat plugin, som vil tildele sin egen filsystem-demo-mappe. Det giver os en målmappe til at gemme .txt-filen og kontrollere skrivetilladelser.

Først og fremmest, lad os oprette demoversiden for at vise vores formular under menuen Værktøjer:

/*** Create Demo page (under Tools menu)***/add_action('admin_menu', 'filesystem_demo_page');function filesystem_demo_page() {add_submenu_page( 'tools.php', 'Filesystem API Demo page', 'Filesystem Demo', 'upload_files', 'filesystem_demo', 'filesystem_demo_screen' );}function filesystem_demo_screen() {$form_url = "tools.php?page=filesystem_demo";$output = $error = '';/*** write submitted text into file (if any)* or read the text from file - if there is no submission**/if(isset($_POST['demotext'])){//new submissionif(false === ($output = filesystem_demo_text_write($form_url))){return; //we are displaying credentials form - no need for further processing}  elseif (is_wp_error ($ output)) {$error = $output->get_error_message();$output = '';}  } ellers {// læs fra filif (false === ($ output = filesystem_demo_text_read ($ form_url))) {return;  // vi viser legitimationsoplysninger danner intet behov for yderligere behandling} elseif (is_wp_error ($ output)) {$error = $output->get_error_message();$output = '';}  } $ output = esc_textarea ($ output);  // undslippe til udskrivning?> 

Filsystem API Demo side

Når vi viser vores side (filesystem_demo_screen), kontrollerer vi om tilgængeligheden af ​​tekstindsendelse. Hvis det eksisterer, forsøger vi at skrive det i en test.txt-fil, ellers forsøger vi at finde en sådan fil i plugin-mappen og læse dens indhold for at blive inkluderet i textarea. Endelig udskriver vi en grundlæggende formular til indtastning af tekst. Af hensyn til læsbarhed blev disse skrive- og læseprocesser adskilt i deres egne funktioner.

Filesystem API demo

For at undgå overlapning af de samme initialiseringstrin er den delte hjælper blevet oprettet. Det kalder request_filesystem_credentials først til at registrere den tilgængelige forbindelsesmetode og få legitimationsoplysninger. Hvis det lykkedes, kalder det derefter WP_Filesystem for at indlede $ wp_filesystem med givne data.

/*** Initialize Filesystem object** @param str $form_url - URL of the page to display request form* @param str $method - connection method* @param str $context - destination folder* @param array $fields - fileds of $_POST array that should be preserved between screens* @return bool/str - false on failure, stored text on success**/function filesystem_init($form_url, $method, $context, $fields = null) {global $wp_filesystem;/* first attempt to get credentials */if (false === ($creds = request_filesystem_credentials($form_url, $method, false, $context, $fields))) {/*** if we comes here - we don't have credentials* so the request for them is displaying* no need for further processing**/return false;}/* now we got some credentials - try to use them*/if (!WP_Filesystem($creds)) {/* incorrect connection data - ask for credentials again, now with error message */request_filesystem_credentials($form_url, $method, true, $context);return false;}return true; //filesystem object successfully initiated}

Skrive til filkode ser sådan ud:

/*** Perform writing into file** @param str $form_url - URL of the page to display request form* @return bool/str - false on failure, stored text on success**/function filesystem_demo_text_write($form_url){global $wp_filesystem;check_admin_referer('filesystem_demo_screen');$demotext = sanitize_text_field($_POST['demotext']); //sanitize the input$form_fields = array('demotext'); //fields that should be preserved across screens$method = ''; //leave this empty to perform test for 'direct' writing$context = WP_PLUGIN_DIR . '/filesystem-demo'; //target folder$form_url = wp_nonce_url($form_url, 'filesystem_demo_screen'); //page url with nonce valueif(!filesystem_init($form_url, $method, $context, $form_fields))return false; //stop further processign when request form is displaying/** now $wp_filesystem could be used* get correct target file first**/$target_dir = $wp_filesystem->find_folder($context);$target_file = trailingslashit($target_dir).'test.txt';/* write into file */if(!$wp_filesystem->put_contents($target_file, $demotext, FS_CHMOD_FILE))return new WP_Error('writing_error', 'Error when writing file'); //return error objectreturn $demotext;}

I denne del definerede vi nogle nødvendige parametre:

  • $ demotext - sendt tekst til skrive
  • $ form_fields - element i $ _POST arrayet, der gemmer vores tekst og skal bevares
  • $ metode - transportmetode, vi lader den stå tom for at registrere automatisk
  • $ kontekst - målmappe (pluginens en)

Derefter indledte vi det globale $ wp_filesystem objekt ved hjælp af den hjælperfunktion jeg tidligere beskrev. I tilfælde af succes opdager vi den korrekte vej til målmappen og skriver den indsendte tekst ind i den ved hjælp af put_contents metode for $ wp_filesystem objektet.

Koden til læsning fra filen ser sådan ud:

/*** Read text from file** @param str $form_url - URL of the page where request form will be displayed* @return bool/str - false on failure, stored text on success**/function filesystem_demo_text_read($form_url){global $wp_filesystem;$demotext = '';$form_url = wp_nonce_url($form_url, 'filesystem_demo_screen');$method = ''; //leave this empty to perform test for 'direct' writing$context = WP_PLUGIN_DIR . '/filesystem-demo'; //target folderif(!filesystem_init($form_url, $method, $context))return false; //stop further processing when request forms displaying/** now $wp_filesystem could be used* get correct target file first**/$target_dir = $wp_filesystem->find_folder($context);$target_file = trailingslashit($target_dir).'test.txt';/* read the file */if($wp_filesystem->exists($target_file)){ //check for existence$demotext = $wp_filesystem->get_contents($target_file);if(!$demotext)return new WP_Error('reading_error', 'Error when reading file'); //return error object}return $demotext;}

Denne funktion fungerer på samme måde som tidligere beskrevet, men den bruger get_contents til at læse fra målfilen.

Konklusion

Når du arbejder med lokale filer, kommer en WordPress-tema eller plugin-udvikler i kontakt med sikkerheds- og kompatibilitetsproblemer, der lægger stor stress på holdet og tilføjer lange timer til projektets livscyklus. Ved at stole på Filsystem API kan disse problemer sidesteges effektivt. Så næste gang du finder dig selv at skrive fwrite i dit plugin kode, overveje dette alternativ den sundere løsning.

Du kan download en demo af denne kode her , og tilpasse det til dine behov.