Miten PHP-kielellä voi tehdä sivun, joka luo kansion, jossa on muutama tiedosto?
<?php mkdir("/uusikansio", 0700); $uusitiedosto1 = fopen("/uusikansio/ekatiedosto.txt", "w"); fclose($uusitiedosto1); ?>
Muista, että jos haluat, että uusi tiedosto luodaan esim. public_html-kansion sisään mkdir pitäisi olla "/public_html/uusikansio" ja $uusitiedosto1 sen mukaan. Jos teet tätä paikallisesti koneella, se menee luultavasti ihan roottiin. (Esim. testasin juuri MAMP:illa, omalla koneella. Suoritin osoitteessa localhost:8888/ohj/, ja se EI tehnyt uutta kansiota ja tiedostoa tuohon ohj-kansioon vaan paikalliseen roottiin (/).). Jos haluat tekstitiedostoon jotain lisätä, lisää $uusitiedosto1-variablen ja fclosen väliin (onkohan sillä edes väliä :O, en tiedäkkään):
file_put_contents("/uusikansio/ekatiedosto.txt", "heippa", FILE_APPEND);
Jos kyseinen koodi ei toimi, suosittelen miettimään, miten voit antaa oikeat oikeudet palvelimelle (muokata tiedostoa). Google on kaverisi.
appendiin "a" (jos ylempi ei tomi). Append kirjoittaa aina tiedoston loppuun halutun tekstin.
joah kirjoitti:
Muista, että jos haluat, että uusi tiedosto luodaan esim. public_html-kansion sisään mkdir pitäisi olla "/public_html/uusikansio" ja $uusitiedosto1 sen mukaan. Jos teet tätä paikallisesti koneella, se menee luultavasti ihan roottiin.
Kyllä se nyt menee juureen ihan missä tahansa ympäristössä, koska polku osoittaa sinne. Parempi joko käyttää suhteellisia polkuja tai sitten hakea www-juuren polku ajonaikaisesti jollain php:n tarjoamalla mekanismilla.
fopen ja file_put_contents eivät missään tapauksessa kuulu yhteen. Jos tiedosto on avattu ensiksi mainitulla, siihen voi kirjoittaa funktiolla fwrite. Jos taas käytetään jälkimmäistä, fopen (ja fclose) on turha.
Lisäksi polun alussa /-merkki todellakin osoittaa tiedostojärjestelmän juureen, joten sitä ei yleensä kuulu käyttää.
Oikea ratkaisu olisi siis esimerkiksi tällainen:
<?php mkdir("hakemisto", 0700); touch("hakemisto/tyhja_tai_muuttumaton_tiedosto"); file_put_contents("hakemisto/tyhja_tiedosto", ""); file_put_contents("hakemisto/taysi_tiedosto", "dataa");
Metabolix kirjoitti:
Oikea ratkaisu olisi siis esimerkiksi tällainen:
<?php mkdir("hakemisto", 0700);
En kyllä ihan varauksetta uskaltaisi kutsua tätä "oikeaksi ratkaisuksi", ennemmin jopa vaaralliseksi. Suhteellinen hakemistopolku on suhteessa PHP:n "ajohakemistoon" (current working directory) joka taas riippuu siitä mistä ja miten ohjelmaa ajetaan, onko välissä includeja eri hakemistoissa olevista tiedostoista tai jopa PHP:n versiosta.
Minusta "oikea ratkaisu" on tapauskohtaista. Parempia vaihtoehtoja olisi esimerkiksi käyttää "juurena" tiedoston sijaintia ja määritellä haluttu paikka hakemistolle suhteessa siihen näin:
mkdir(__DIR__."/../uudetjutut/hakemisto", 0700); touch(__DIR__."/../uudetjutut/hakemisto/tyhja_tai_muuttumaton_tiedosto");
tai vaihtoehtoisesti haluttu kohdehakemisto voitaisiin määritellä ohjelman asetuksissa joko absoluuttisena tai suhteessa johonkin toiseen tunnettuun hakemistoon ja välittää sieltä parametrina tälle skriptille. Käyttö olisi sitten jonekin näin:
mkdir($CONFIG['target_dir']."/hakemisto", 0700); touch($CONFIG['target_dir']."/hakemisto/tyhja_tai_muuttumaton_tiedosto");
Oleellista tästä tulee silloin kun tehdään yleiskäyttöisiä funktioita tai luokkia, joita voidaan käyttää includetettuna useista eri hakemistoissa sijaitsevista tiedostoista käsin.
Luokkien kanssa olisi kylläkin hyvä käyttää auto includea, jolloin polut määritellään tavallisesti nimiavaruuskohtaisesti.
Absoluuttisia polkuja käyttämällä ei saavuteta mitään oleellista parannusta tässä tapauksessa. Kyse ei ole tietoturvastakaan, koska täytyy voida olettaa, että kaikki järjestelmään tuodut php-tiedostot ovat turvallisia. Periaatteessa millään funktiolla ei myöskään pitäisi olla tarvetta muuttaa työhakemistoa vaan sen sijaan niiden pitäisi käyttää täydellisiä polkuja sisäisissä parametreissaan yms.
The Alchemist kirjoitti:
Luokkien kanssa olisi kylläkin hyvä käyttää auto includea, jolloin polut määritellään tavallisesti nimiavaruuskohtaisesti.
Ei tuollaista olekaan. Jos meinaat PHP:n autoloading-mekanismia, niin sen yhteydessä tehdään yleensä aivan tavallinen include. Tällöin olisi erityisesti syytä määritellä hakemistopolku muuten kuin suhteessa "ajohakemistoon" koska ohjelmoijan voi olla hakala tietää mikä kulloinenkin ajohakemisto on tai se voi vaihdella jopa yhden projektin sisälläkin.
The Alchemist kirjoitti:
Absoluuttisia polkuja käyttämällä ei saavuteta mitään oleellista parannusta tässä tapauksessa. Kyse ei ole tietoturvastakaan, koska täytyy voida olettaa, että kaikki järjestelmään tuodut php-tiedostot ovat turvallisia. Periaatteessa millään funktiolla ei myöskään pitäisi olla tarvetta muuttaa työhakemistoa vaan sen sijaan niiden pitäisi käyttää täydellisiä polkuja sisäisissä parametreissaan yms.
Ei se absoluuttinen polku ollutkaan mikään ainoa "oikea ratkaisu" vaan yksi Metabolixin ehdottamaa tapaa parempi tapa määritellä polku sovelluksen asetuksissa. Tällöin tiedostot ainakin luodaan aina samaan paikkaa riippumatta miten ja mistä ohjelmaa ajetaan. Monissa ohjelmissa voi esim. olla useita eri front controllereita tai ylläpitoskriptejä jotka määrittelevät ajohakemiston erilaisiksi.
Miksi asetuksissa annettava absoluuttinen polku olisi huono?
Tukki kirjoitti:
Miksi asetuksissa annettava absoluuttinen polku olisi huono?
Esimerkiksi siksi, että kysyjä halusi tehdä yhden sivun eikä mitään entterprise framework web applikaatiota. On melko ilmeistä, että tällä kysyjällä ei ole ”eri front controllereita tai ylläpitoskriptejä” ja että sellaisiin soveltuvan ratkaisun tyrkyttäminen todennäköisesti aiheuttaa enemmän hämmennystä ja ongelmia kuin ratkaisee.
Jossain amatöörin include-sekamelskassa mainitsemasi __DIR__ voi kyllä olla hyödyllinen. PHP:n tavallisimmassa käyttötapauksessa kuitenkin työhakemisto on täysin ilmeinen.
Mainittakoon vielä, että aiemman esimerkkini keskeinen sisältö ei ollut siinä, että "hakemisto" olisi välttämättä suhteellinen polku, vaan "hakemisto" oli eräänlainen placeholder, jossa aloittavan /-merkin puuttuminen korjasi ensimmäisen vastaajan aiheuttamaa väärinkäsitystä polkujen toiminnasta. Olennaisempaa sisältöä olivat erilaiset
Metabolix kirjoitti:
Jossain amatöörin include-sekamelskassa mainitsemasi __DIR__ voi kyllä olla hyödyllinen.
Melko asenteellista. Kerropa sitten huviksesi miten sellainen ohjelma rakennettaisiin ilman __DIR__-vakiota (tai absoluuttista polkua), jossa ajettavia PHP-tiedostoja on useammassa eri hakemistossa, niin että uudet tiedostot tulisivat kuitenkin aina samaan hakemistoon ja joka ei silti olisi amatöörin include-sekamelska. Vai onko niin että kaikki projektit joissa on yli yksi hakemisto ja joita ajetaan useista eri sijainneista tai joissa ylipäänsä samaa koodia hyödynnetään useissa eri työhakemistoissa ovat amatöörin include-sekamelskoja?
Tukki kirjoitti:
– –
En ihan tiedä, mitä yrität sanoa tai mitä kohtaa viestistäni et ehkä ymmärtänyt.
Jos projekti on niin hieno, että siinä ajetaan koodia ”useista eri sijainneista”, varmasti silloin koodi ja data ovat eri paikoissa ja projektissa on ehdottamasi asetustiedosto ja se on hyvä. En ole tästä muuta väittänyt. Useimmat (aloittelijoiden) projektit eivät kuitenkaan ole niin hienoja.
Toinen ehdotuksesi, että käytettäisiin __DIR__-taikavakiota, on siinä mielessä jo idealtaan rikki, että (1) includella kannattaisi yleensä liittää vain luokkia ja funktioita sisältäviä tiedostoja ja (2) näiden tiedostojen sekaan ei varmasti pitäisi luoda dynaamisesti mitään uutta sisältöä. Toisin sanoen __DIR__ on tässä tilanteessa purkkaviritelmä, jolla paikataan lähtökohtaisesti huonoa ja vaarallista koodia, kun ei osata muuten pitää hakemistoja kuosissa.
Siis mielestäni yksinkertaisessa projektissa, jossa tehdään (kuten kysyttiin) yhtä tavanomaista PHP-sivua, kannattaa käyttää yksinkertaisesti suhteellista polkua ja monimutkaisessa projektissa kannattaa tehdä oikeasti oikein eli käyttää vaikka sitä asetustiedostoa. __DIR__-vakion sekoittaminen tähän kuvioon näyttää lähinnä siltä, että homma on lähtenyt lapasesta.
Metabolix kirjoitti:
En ihan tiedä, mitä yrität sanoa tai mitä kohtaa viestistäni et ehkä ymmärtänyt.
Koitetaan uudestaan.
Ihan aidosti yritin kysyä, että miten mielestäsi polku kannattaisi määritellä hieman monimutkaisemmassa projektissa, mikäli __DIR__-vakiota ei tulisi käyttää missään vaiheessa. Olet oikeassa että yleiskäyttöisten luokkien tai funktioiden sisällä __DIR__ on huono ja juuripolku tulisi antaa niille parametrina asetuksista. Kommentissani se oli lähinnä nopea korjaus ehdottamaasi "oikeaan ratkaisuun", millä saa aikaiseksi mielestäni hieman loogisemman toiminnan vähän useammassa tilanteessa, mutta täysin saman toiminnan yksikertaisessa tilanteessa. Erityisesti ihmettelin myös kommenttiasi että työhakemistoon suhteellinen polku olisi "oikeampi" kuin tiedostojärjestelmän juureen suhteellinen polku.
Metabolix kirjoitti:
(1) includella kannattaisi yleensä liittää vain luokkia ja funktioita sisältäviä tiedostoja
Totta, mutta muitakin tiedostoja kuitenkin liitetään includella varsinkin aloitttelijoiden toimesta ja silloin __DIR__."/polku" on parempi kuin pelkkä "polku".
Metabolix kirjoitti:
(2) näiden tiedostojen sekaan ei varmasti pitäisi luoda dynaamisesti mitään uutta sisältöä.
__DIR__:n käyttö ei varsinaisesti kerro mitään siitä minkä sekaan uusi sisältö luodaan vaan määrittellee ainoastaan polun suhteessa tiedostoon vastakohtana työhakemistoon tai tiedostojärjestelmän juureen suhteellisille poluille.
Mutta jotenkin se parametrinakin annettava polku on kuitenkin määriteltävä sinne asetuksiin ja se miten se kannattaa tehdä on tapauskohtaista, kuten sanoin:
1) Jos juuripolku on luonteeltaan sellainen että se halutaan aina pitää suhteessa projektiin samana, se on luontevaa määritellä __DIR__:n avulla jossain tiedostossa, joka on projekthakemistossa aina samassa sijainnissa, ja lukea sieltä esimerkiksi asetuksiin. Jos asetustiedosto on PHP:tä (tai muuten ohjelmoitava) juuripolun voisi määritellä suoraan siellä __DIR__:n avulla. Tämä sopii esim. luokkatiedostojen include-polkujen tai lokitiedoston sijainnin määrittämiseen jolloin asetuksia ei tarvitse muuttaa jos projekti asennetaan toiseen hakemistoon.
2) Jos polku halutaan osoittaa aina tiettyyn paikkaan riippumatta siitä mihin projekti on asennettu, voidaan juuripolku määritellä asetuksiin absoluuttisena. Tällöin polku pitää todennäköisesti määritellä aina erikseen projektia asennettaessa.
En keksi miten tekisit kohdan 1 paremmin ilman että __DIR__:iä tai vastaavaa menetelmää käytettäisiin missään kohtaa.
Tukki kirjoitti:
Ihan aidosti yritin kysyä, että miten mielestäsi polku kannattaisi määritellä hieman monimutkaisemmassa projektissa
Ahaa, no itse taas yritin nimenomaan selittää, että ilmiselvästi tässä keskustelussa ei alusta saakka ole kysymys monimutkaisemmasta projektista vaan todellakin yhdestä ainoasta tavallisesta PHP-sivusta, jolloin mielestäni voi aivan hyvin käyttää suhteellista polkua (ja jos se ei toimi, tiedetäänkin jo, että koodissa on tehty includella tai chdirillä jotain typerää).
Monimutkaisemmassa projektissa saa puolestani käyttää __DIR__-vakiota jostain yhdestä lähteestä sivuston juuren määrittelyyn. Tämä on kuitenkin aivan eri tilanne kuin sinun aiemmin esittämäsi, jossa __DIR__-vakio on tungettu suoraan mkdir-kutsuun.
Aihe on jo aika vanha, joten et voi enää vastata siihen.