<?php function php($s) { return '<div style="font-size: 12px">' . highlight_string(html_entity_decode(stripslashes($s)), True) . '</div>'; } function archive($var) { $var = file_get_contents($var); $search = array('/\[koodi\](.*?)\[\/koodi\]/ise'); $replace = array("php('\\1')"); $var = preg_replace($search, $replace, $var); echo $var; }
Tuon näköisen systeemin onnistuin tekemään, mutta on yksi ongelma. Jos sivulla joka ajetaan archive-funktion läpi, on php-koodia, niin tämä tulostetaan sellaisenaan lähdekoodiin. Mitä tein väärin, että se tekee niin PHP:n ajamisen sijaan?
Mitä tarkoitat? Voisitko antaa esimerkin tiedostosta, toivomistasi käsittelyvaiheista ja tulosteesta?
Tulos on sama, kuin laittaisi PHP-koodia *.html sivulle jota ei ajeta PHP tulkin läpi. Eli, jos sivulla lukee
<?php echo "Hello world!"; ?>
niin archive-funktion läpiajettaessa PHP tulkitaan normaalina kielenä, eikä ajeta PHP-tulkin läpi. Ylläoleva tulostaa tyhjän sivun, jonka lähdekoodissa lukee tuo pätkä.
Käytät file_get_contents(); funktiota, joka ottaa tiedostosisällön stringii. Haluat varmaa käyttää include-funktiota, mutta jotta sen käyttäminen onnistuisi stringinä, tarvitset seuraavaa koodinpätkää:
<?php function get_include_contents($file) { if(is_file($file)) { ob_start(); include $file; $result = ob_get_contents(); ob_end_clean(); return $result; } return false; } ?>
Ja sitten file_get_contentsin sijasta käytät get_include_contents.
Muuten hyvä, mutta kuten aikaisemmasta viestistä huomaat, niin [koodi]-tagien sisällä oleva koodi pitäisi tulostaa väritettynä. Nyt käy siten, että kaikki koodit suoritetaan.
Palataanpa vähän olennaisempiin asioihin, jotka jätit välistä. Onko tarkoituksesi tulostaa jonkin valitun PHP-tiedoston koodi väritettynä?
(Nyt yritetään neuvoa ennen kuin tiedetään mitä oikeastaan haet takaa.)
Ihan sama asia kuin Ohjelmointiputkassa: [ koodi]-tagien sisältö tulostetaan väritettyinä, ja jos sivulla on muuta PHP-koodia niin tämä ajetaan PHP-tulkin läpi. HTML:n kanssa menetellään normaalisti (Kuten file_get_contents() tekeekin).
Helpoin tapa varmistaa ettei koodia suoriteta on käyttää htmlentities('<?php echo 'koodi jotai ei suoriteta'; ?>');, mikäli siis mahdollista tilanteessasi.
En nyt ihan ymmärrä. Mitä pitäisi tehdä, että postittamasi funktio ei käsittelisi [koodi]-tagien välissä olevaa dataa "omakseen", vaan antaisi php() funktion suorittaa sen?
Todettakoon, että Putkassa on käytössä oma BBCode-systeeminsä. Viesti on siis kokonaan säilötty tekstinä, mm. (kai) htmlspecialchars suoritetaan kertaalleen koko viestille ja sen jälkeen muutetaan tagit HTML:ksi ja väritetään toki koodikin. Viestit on ymmärtääkseni säilötty tietokantaan. Tämän vuoksi file_get_contentsin ym. sotkeminen mukaan on hieman hämmentävää, ainakin jos tarkoituksena on tehdä oma BBCode-systeemi.
Suosittelen tutkimaan foorumijärjestelmien BBCode-koodia ja Geshi saattaa kiinnostaa myös.
Macro kirjoitti:
En nyt ihan ymmärrä. Mitä pitäisi tehdä, että postittamasi funktio ei käsittelisi [koodi]-tagien välissä olevaa dataa "omakseen", vaan antaisi php() funktion suorittaa sen?
Mistä koodi-tagien välissä oleva data ensinnäkin tulee? Uskoisin että pystyt vaikuttamaan siellä, lisäämällä koodi-tagien sisällä olevan koodin ympärillä htmlentities()-funktiot joka tekee merkeistä html-entiteettejä, jolloin koodia ei suoriteta.
Esim:
<?php echo 'tämä koodi on tagien sisällä'; ?>
Korvautuisi tällä:
<?php htmlentities(" <?php echo 'tämä koodi on tagien sisällä'; ?> "); ?>
EDIT:
Jos tekstisi sisältö tulee tietokannasta kannattaa käyttää htmlentities()-funktiota jo tallentaessa sitä sinne.
Saisi sen varmaan näinkin, tosin vaikeamman kautta. arvhive-funktion paramentti $var ottaa arvokseen sivun osoitteen, jonka tämä sitten hakee.
-tagien välissä oleva data pitäisi ajaa php()-funktion läpi, ja muu tuon get_include_contents()-funktion läpi. [koodi PHP]<?php function php($s) { return '<div style="font-size: 12px">' . highlight_string(html_entity_decode(stripslashes($s)), true) . '</div>'; } function archive($var) { $var = get_include_contents($var); $search = array('/\[koodi\](.*?)\[\/koodi\]/ise'); $replace = array("php('\\1')"); $var = preg_replace($search, $replace, $var); echo $var; }
Macro kirjoitti:
Saisi sen varmaan näinkin, tosin vaikeamman kautta. arvhive-funktion paramentti $var ottaa arvokseen sivun osoitteen, jonka tämä sitten hakee. [koodi]-tagien välissä oleva data pitäisi ajaa php()-funktion läpi, ja muu tuon get_include_contents()-funktion läpi.
En usko että tämä lähestymistapa voisi toimia, saati sitten olla mahdollista. Et tietääkseni pysty mitenkään muokkaamaan dataa ensin muuttujassa ja sitten suorittamaan sitä, vaan sinun pitää muokata dataa jo ennen kuin se suoritetaan.
EDIT: Mikäköhän kirjoitustaitoani vaivaa...
En ymmärrä, että mitä koitat ajaa takaa tuolla. Miten siis suoritan kaiken muun paitsi [koodi]-tagien sisällön, jonka syntaxi-värityksen annan php() funktiolla? Jostain syystä ei tee mieli pyytää esimerkkiä, mutta se voisi nyt kyllä helpottaa.
Siis onko tavoitteesi tämä:
<?php echo "Tuloste\n"; ?> [kooditagi] <?php echo "Väritys\n"; ?> [/kooditagi]
Tuloste <?php echo "Väritys\n"; ?>
Ensimmäinen PHP-osuus ajettiin ja se tulosti yhden sanan. Kooditagien sisältö on HTML-enkoodattu ja näkyy sivulla alkuperäisessä muodossaan. (Lisäksi sekaan tulisi väritystä varten tageja, mutta nyt en selkeyden vuoksi laittanut niitä.)
Entä miten tämän koodin pitäisi toimia:
<?php for ($i = 0; $i < 10; ++$i) { ?> [kooditagi] <?php echo $i; ?> [/kooditagi] <?php }
(Voit kokeilla tavallisella PHP-sivulla, mitä tuo tavallisesti tekee.)
Voit esimerkiksi poimia kooditagien välisen osuuden säännöllisellä lausekkeella ja enkoodata sen ennen koodin ajamista. Tämä tapa kuitenkin toimii aika omituisesti, jos kooditageja esiintyy muun PHP-koodin seassa. Mutkikkaammalla lausekkeella saisi paremman lopputuloksen, mutta sellaisen saat opetella itse kirjoittamaan. (Katso oppaan lisäksi vaikka koodivinkkiä C++-koodin värityksestä.)
<?php function varita($osuma) { return htmlspecialchars($osuma[1]); } eval('?>'.preg_replace_callback('#\\[kooditagi\\](.*?)\\[/kooditagi\\]#ms', 'varita', file_get_contents('testi.php'))); ?>
Edit: Esimerkki.
Kiitos Metabolix! Muistinkin, että PHP:ssä on eval() funktio, mutta en älynnyt/osannut käyttää.
Aihe on jo aika vanha, joten et voi enää vastata siihen.