Wat u moet weten over .htaccess. Hoofdfunctieparameters (argc, argv)

Borland C++ ondersteunt er drie belangrijkste argument(). De eerste twee zijn de traditionele argc en argv. Dit zijn de enige argumenten voor main() die zijn gedefinieerd door de ANSI C-standaard. Ze maken het mogelijk dat opdrachtregelargumenten aan het programma worden doorgegeven. Opdrachtregelargumenten zijn de informatie die volgt op de programmanaam op de opdrachtregel besturingssysteem. Wanneer een programma bijvoorbeeld wordt gecompileerd met behulp van de Borland-lijncompiler, wordt dit doorgaans getypt als bcc programmanaam

Waar programmanaam is een programma dat gecompileerd moet worden. De programmanaam wordt als argument aan de compiler doorgegeven.

De parameter argc bevat het aantal opdrachtregelargumenten en is een geheel getal. Het is altijd gelijk ten minste, 1 omdat de programmanaam als eerste argument kwalificeert. De parameter argv is een verwijzing naar een reeks tekenaanwijzers. Elk element van deze reeks verwijst naar een opdrachtregelargument. Alle opdrachtregelargumenten zijn tekenreeksen. Alle getallen worden door het programma omgezet naar een intern formaat. Volgende programma drukt "Hallo" af, gevolgd door de gebruikersnaam als deze direct na de programmanaam wordt getypt:

#erbij betrekken

{
als(argc!=2)
{
printf("Je bent vergeten je naam in te typen\n");
retour 1;
}
printf("Hallo %s", argv);
retour 0;
}

Als je belt dit programma naam, en de gebruikersnaam is Sergey, en om het programma te starten typt u:
naam Sergej.
Als resultaat van het programma verschijnt het volgende:
"Hallo Sergej."

Opdrachtregelargumenten moeten worden gescheiden door spaties of tabs. Komma's, puntkomma's en soortgelijke tekens worden niet als scheidingstekens beschouwd. Bijvoorbeeld:

Bestaat uit drie regels, terwijl

Kruid, Rick, Fred

Dit is één regel; komma's zijn geen scheidingstekens.

Als u een tekenreeks met spaties of tabs als één enkel argument wilt doorgeven, moet u deze insluiten dubbele aanhalingstekens. Dit is bijvoorbeeld een argument:

"Dit is een proef"

Het is belangrijk om argv correct te declareren. Meest typische methode is:

Lege haakjes geven aan dat de array geen vaste lengte heeft. Je hebt toegang individuele elementen met behulp van argv-indexering. Argv verwijst bijvoorbeeld naar de eerste regel, die altijd de programmanaam bevat. argv verwijst naar de volgende regel, enzovoort.

Hieronder staat klein voorbeeld over het gebruik van opdrachtregelargumenten. Hij telt af omgekeerde volgorde van de waarde die is opgegeven op de opdrachtregel en genereert een signaal wanneer deze nul bereikt. Merk op dat het eerste argument een getal bevat dat is omgezet in een geheel getal met behulp van standaard functie atoi(). Als de string "display" aanwezig is als tweede argument, wordt de teller zelf op het scherm weergegeven.

/* telprogramma */

#erbij betrekken
#erbij betrekken
#erbij betrekken
int hoofd(int argc, char *argv)
{
int disp, tellen;
als(arg<2)
{
printf("Je moet de lengte van de telling invoeren\n");
printf("op de opdrachtregel. Probeer het opnieuw.\n");
retour 1;
}
if (argc==3 && !strcmp(argv,"display")) disp = 1;
anders disp = 0;
for(count=atoi(argv); count; -count)
if (disp) printf("%d ", tellen);
printf("%c", "\a"); /* op de meeste computers is dit een oproep */
retour 0;
}

Houd er rekening mee dat als er geen argumenten zijn opgegeven, er een foutmelding verschijnt. Dit is het meest typerend voor programma's die opdrachtregelargumenten gebruiken om instructies te geven als er een poging wordt gedaan om het programma uit te voeren zonder de juiste informatie.

Om toegang te krijgen tot individuele opdrachtregeltekens, voegt u een tweede index toe aan argv. Het volgende programma drukt bijvoorbeeld alle argumenten waarmee het is aangeroepen af, één teken tegelijk:

#erbij betrekken
int hoofd(int argc, char *argv)
{
int t, ik;
voor(t=0; t {
ik = 0;
terwijl(argv[t][i])
{
printf("%c", argv[t][i]);
}
printf(" ");
}
retour 0;
}

We moeten niet vergeten dat de eerste index bedoeld is voor toegang tot een string, en de tweede voor toegang tot een teken in een string.

Normaal gesproken worden argc en argv gebruikt om bronopdrachten te verkrijgen. Het is theoretisch mogelijk om maximaal 32767 argumenten te hebben, maar bij de meeste besturingssystemen kun je daar niet eens in de buurt komen. Meestal worden deze argumenten gebruikt om een ​​bestandsnaam of opties op te geven. Het gebruik van opdrachtregelargumenten geeft het programma een professionele uitstraling en maakt het mogelijk het programma in batchbestanden te gebruiken.

Als u het WILDARGS.OBJ-bestand opneemt dat bij Borland C++ wordt geleverd, kunt u sjablonen gebruiken in *.EXE-typeargumenten. (Borland C++ verwerkt automatisch jokertekens en verhoogt argc dienovereenkomstig.) Als u bijvoorbeeld WILDARGS.OBJ met het volgende programma verbindt, zal het u vertellen hoeveel bestanden overeenkomen met de bestandsnaam die is opgegeven op de opdrachtregel:

/* Koppel dit programma met WILDARGS.OBJ */

#erbij betrekken
int hoofd(int argc, char *argv)
{
registreer int i;
printf("%d bestanden komen overeen met de opgegeven naam\n", argc-1);
printf("Het zijn: ");
voor(i=1; ik printf("%s ", argv[i]);
retour 0;
}

Als we dit programma WA noemen en het vervolgens als volgt uitvoeren, krijgen we het aantal bestanden met de EXE-extensie en een lijst met de namen van deze bestanden:

Naast argc en argv biedt Borland C++ ook een derde opdrachtregelargument -env. Met de parameter env kan een programma toegang krijgen tot informatie over de besturingssysteemomgeving. De parameter env moet volgen op argc en argv en wordt als volgt gedeclareerd:

Zoals u kunt zien, wordt env op dezelfde manier gedeclareerd als argv. Net als argv is het een verwijzing naar een array van strings. Elke regel is een omgevingsreeks die door het besturingssysteem wordt gedefinieerd. De parameter env heeft geen equivalente parameter argc die aangeeft hoeveel omgevingsrijen er zijn. In plaats daarvan is de laatste regel van de omgeving nul. Het volgende programma drukt alle omgevingsreeksen af ​​die momenteel in het besturingssysteem zijn gedefinieerd:

/* dit programma toont alle omgevingsregels */

#erbij betrekken
int main(int argc, char *argv, char *env)
{
int;
voor(t=0; env[t]/ t++)
printf("%s\n", env[t]);
retour 0;
}

Houd er rekening mee dat hoewel argc en argv niet door het programma worden gebruikt, ze wel aanwezig moeten zijn in de parameterlijst. C kent de parameternamen niet. In plaats daarvan wordt het gebruik ervan bepaald door de volgorde waarin de parameters worden gedeclareerd. In feite kunt u de parameter noemen hoe u maar wilt. Omdat argc, argv en env traditionele namen zijn, is het beter om ze te blijven gebruiken, zodat iedereen die het programma leest onmiddellijk kan begrijpen dat dit argumenten zijn voor de functie main().

Een typische taak voor programma's is het opzoeken van een waarde die is gedefinieerd in een omgevingsreeks. Dankzij de inhoud van de PATH-regel kunnen programma's bijvoorbeeld zoekpaden gebruiken. Het volgende programma laat zien hoe u tekenreeksen kunt vinden die standaardzoekpaden declareren. Het gebruikt de standaardbibliotheekfunctie strstr(), die het volgende prototype heeft:

Char *strstr(const char *str1, const char *str2);

De functie strstr() zoekt naar de string waarnaar str1 verwijst in de string waarnaar str2 verwijst. Als een dergelijke string wordt gevonden, wordt een verwijzing naar de eerste positie geretourneerd. Als er geen overeenkomsten worden gevonden, retourneert de functie NULL.

/* het programma zoekt in de omgevingsstrings naar een regel met PATH */

#erbij betrekken
#erbij betrekken
int main (int argc, char *argv, char *env)
{
int;
voor(t=0; env[t]; t++)
{
if(strstr(env[t], "PAD"))
printf("%s\n", env[t]);
}
retour 0;
}

Dit artikel is ontstaan ​​uit een idee om geavanceerde training te geven aan onze technische ondersteuningsmedewerkers over mod_rewrite. De praktijk heeft geleerd dat ondersteuningsteams, na bestudering van het grote aantal beschikbare schoolboeken in het Russisch, goed zijn in het oplossen van standaardproblemen, maar dat het zelfstandig opstellen van regels gebeurt met vallen en opstaan. Het probleem is dat een goed begrip van hoe mod_rewrite werkt het bestuderen van de originele Engelse documentatie vereist, gevolgd door aanvullende uitleg of urenlang experimenteren met RewriteLog.

Het artikel beschrijft hoe mod_rewrite werkt. Als u de principes van de werking ervan begrijpt, kunt u het effect van elke richtlijn duidelijk begrijpen en u duidelijk voorstellen wat er op een of ander moment gebeurt binnen mod_rewrite bij het verwerken van richtlijnen.

Ik neem aan dat de lezer al bekend is met wat mod_rewrite is, en ik zal de basisprincipes ervan niet beschrijven, die gemakkelijk op internet te vinden zijn. Er moet ook worden opgemerkt dat het artikel het werk van mod_rewrite behandelt bij het gebruik van de richtlijnen in het .htaccess-bestand. Verschillen bij het werken in context uiteengezet in.

Dus je hebt mod_rewrite bestudeerd, verschillende RewriteRules gecompileerd en bent erin geslaagd eindeloze omleidingen tegen te komen, het geval waarin een regel om de een of andere reden je verzoek niet opvangt, evenals de onvoorspelbare werking van een groep regels wanneer een volgende regel onverwacht een verzoek dat door de vorige regels nauwgezet was voorbereid.

Waarmee werkt RewriteRule?

De eerste RewriteRule krijgt het pad doorgegeven van waar .htaccess zich bevindt naar het opgevraagde bestand. Deze regel begint nooit met "/". Daaropvolgende RewriteRules verzenden het resultaat van eerdere transformaties.

Om goed te begrijpen hoe RewriteRule werkt, moet u eerst definiëren waarmee het werkt. Laten we eens kijken hoe Apache de string ontvangt die aanvankelijk wordt doorgegeven aan de RewriteRule in .htaccess voor verwerking.

Wanneer je voor het eerst met mod_rewrite gaat werken, ga je er logischerwijs van uit dat het met links werkt. Dit is echter niet het geval bij gebruik van mod_rewrite in .htaccess. In feite is het geen link die naar RewriteRule wordt gestuurd, maar het pad naar het opgevraagde bestand.

Vanwege de interne architectuur van Apache kan mod_rewrite, op het moment dat .htaccess in het spel komt, alleen werken op het pad naar het te verwerken bestand. Dit komt door het feit dat voordat het verzoek naar mod_rewrite werd verzonden, het verzoek al door andere modules (bijvoorbeeld mod_alias) had kunnen worden gewijzigd en dat het uiteindelijke pad naar het bestand op de site mogelijk niet langer samenvalt met de oorspronkelijke link. Als mod_rewrite aan de originele referentie zou werken, zou het de actie verbreken van modules die het verzoek daarvoor hadden gewijzigd.

Daarom wordt aan mod_rewrite het absolute pad doorgegeven aan het bestand dat moet worden verwerkt. Mod_rewrite kent ook het pad naar .htaccess, waar de RewriteRule-regels zich bevinden. Om het pad naar het bestand vergelijkbaar te maken met de link waarmee de site-ontwikkelaar wil werken, snijdt mod_rewrite het gedeelte naar het .htaccess-bestand af van het absolute pad.

Het is dus dit pad, waarvan het pad naar .htaccess wordt afgesneden, dat wordt doorgegeven aan de eerste RewriteRule. Bijvoorbeeld:

Verzoek: http://example.com/templates/silver/images/logo.gif DocumentRoot: /var/www/example.com Pad naar bestand: /var/www/example.com/templates/silver/images/logo. gif .htaccess bevindt zich in: /var/www/example.com/templates/.htaccess

De eerste RewriteRule krijgt: silver/images/logo.gif Let op: “templates/” is ook afgekapt. hoe RewriteRule werkt Het pad naar .htaccess wordt samen met de schuine streep afgesneden. Hieruit volgt een gevolg: de regel die aanvankelijk wordt doorgegeven aan de RewriteRule-verwerking begint nooit met "/".

Het is belangrijk om te onthouden wat RewriteRule niet doet. Het verwerkt niet de sitenaam, de argumenten die aan het script worden doorgegeven, en het verwerkt niet de volledige link als de .htaccess zich niet in de hoofdmap van de site bevindt. Dit alles wordt gedaan door RewriteCond, waar we later kort op zullen ingaan. Dus:

# werkt niet - de regel begint met / RewriteRule ^/index.php$ /my-index.php # werkt niet - de sitenaam wordt niet geanalyseerd RewriteRule RewriteRule ^example.com/.* http://www.example .com # zal niet werken - de linkargumenten vallen niet in de RewriteRule RewriteRule index.php\?newspage=(+) news.php?page=$1 # Werkt alleen als .htaccess zich op dezelfde plaats bevindt als de sjablonen map # bijvoorbeeld in de hoofdmap van de site. Dat wil zeggen, als .htaccess in templates/.htaccess staat, zal de regel # NIET werken, omdat mod_rewrite het pad naar .htaccess zal afsnijden en de regel zal eindigen op de RewriteRule # invoer zonder "templates/" RewriteRule ^templates/ common/yandex-geld.gif$-sjablonen/shared/yad.gif

We hebben ontdekt waar RewriteRule mee werkt. Laten we nu kijken hoe het werkt.

Hoe RewriteRule werkt

RewriteRule transformeert eenvoudigweg de string volgens reguliere expressies en dat is alles. RewriteRule werkt op een string, niet op een link of pad naar een bestand.

Zoals we hierboven hebben ontdekt, bevat de RewriteRule-invoer het pad van .htaccess naar het gevraagde bestand. Het is nu het handigst om te abstraheren van paden en links en te overwegen waar RewriteRule mee werkt als een gewone string. Deze tekenreeks wordt doorgegeven van RewriteRule naar RewriteRule, gewijzigd als een van de RewriteRules werkte.

Over het geheel genomen werkt RewriteRule, afgezien van de complexiteit van het gebruik van vlaggen (waarvan we er enkele hieronder zullen bekijken) en de complexiteit van het schrijven van reguliere expressies (waar we in dit artikel niet veel op zullen ingaan), ZEER eenvoudig. Wij hebben de lijn overgenomen. Vergelijk met de reguliere expressie in het eerste argument. Als er een overeenkomst is, vervangt u de gehele tekenreeks door de waarde van het tweede argument. De tekenreeks doorgegeven aan de volgende RewriteRule. Dat is eigenlijk alles. Om duidelijk te illustreren dat RewriteRule specifiek met een string werkt, kun je het volgende fantastische voorbeeld overwegen:

# Verzoek: http://mysite.com/info.html # De eerste RewriteRule zal "info.html" bevatten # Converteer het verzoek naar een willekeurige string. RewriteRule ^info.html$ "Ik zag een schildpad in het hol. En hij danste rock-'n-roll. En hij glimlachte. Al met al was het een heel grappige pop." # "info.html" -> "Ik zag een schildpad..." # Vervang deze regel door een externe link. RewriteRule schildpad https://example.com/information/index.html # "Ik zag een schildpad..." -> "https://example.com/information/index.html" # Vervang de sitenaam! RewriteRule ^(.*)example.com(.*)$ $1example.org$2 # "https://example.com/information/index.html" -> "https://example.org/information/index. html" # Vervang het protocol! RewriteRule ^https:(.*)$ ftp:$1 # "https://example.org/information/index.html" -> "ftp://example.org/information/index.html" # Vervang de laatste link . RewriteRule ^(.*)/index.html$ $1/main.php # "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"

Zoals u kunt zien, maakt het RewriteRule niet uit waarmee het werkt; het transformeert eenvoudigweg de string volgens de argumenten die eraan worden gegeven. Als je wilt, kun je alle data-arrays op een regel opslaan; als je wilt, doorzettingsvermogen en een goede kennis van reguliere expressies hebt, kun je zelfs boter-kaas-en-eieren schrijven op RewriteRule.

Hierbij moet wel een kanttekening worden gemaakt: hoewel RewriteRule met een pure string werkt, is het nog steeds gericht op het werken met links. Daarom zal het op een speciale manier reageren op lijnen die beginnen met

https://

of analogen (het zal onthouden dat we een externe omleiding wilden maken) en naar de "?" (beschouwt de volgende tekens als argumenten die moeten worden vervangen door het verzoek). Daar zijn we op dit moment echter niet in geïnteresseerd - het is belangrijk om te begrijpen dat er geen magie zit in RewriteRule - er is gewoon een string voor nodig en deze verandert op de manier waarop jij het vertelt. We zullen later in het artikel kijken naar externe omleidingen en argumenten; daar is ook iets om over te praten;

Nadat alle transformaties zijn voltooid en de laatste RewriteRule is uitgevoerd, treedt RewriteBase in werking.

Waar wordt RewriteBase voor gebruikt?

Als de resulterende query relatief is en verschilt van de oorspronkelijke query, zal RewriteBase zichzelf links ervan toevoegen. Het is noodzakelijk om RewriteBase op te geven in .htaccess. De waarde ervan is het pad van de siteroot naar .htaccess. RewriteBase wordt alleen uitgevoerd na alle RewriteRules, niet ertussenin.

We hebben hierboven al gezegd dat mod_rewrite, dat werkt in .htaccess, het absolute pad naar het opgevraagde bestand bevat. Om het door te geven aan de RewriteRule, snijdt mod_rewrite het pad naar .htaccess af. Vervolgens wijzigen de RewriteRules de aanvraag één voor één. En nu, nadat het verzoek is gewijzigd, moet Apache het absolute pad herstellen naar het bestand dat het uiteindelijk moet verwerken. RewriteBase is eigenlijk een hack die helpt het oorspronkelijke pad van een bestand te herstellen.

RewriteBase wordt na alle transformaties uitgevoerd. Dit betekent dat het verzoek tussen RewriteRules niet wordt gewijzigd, maar pas van kracht wordt als alle RewriteRules zijn voltooid.

Na alle transformaties kijkt RewriteBase of het resulterende pad relatief of absoluut is. In de context van Apache betekent dit een relatief of absoluut pad, beginnend bij de hoofdmap van de site: images/logo.gif - relatief. /images/logo.gif - absoluut (schuine streep aan het begin). http://example.com/images/logo.gif - de meest absolute van allemaal. Als het pad absoluut is, doet RewriteBase niets. En als het relatief is, voegt RewriteBase zichzelf aan de linkerkant toe. Dit werkt voor zowel interne als externe omleidingen:

# .htaccess bevindt zich in /images/ # RewriteBase is gespecificeerd /images/ RewriteBase /images/ # Verzoek http://example.com/images/logo.gif # De RewriteRule-invoer is "logo.gif" RewriteRule ^logo.gif $ logo -orange.gif # Na RewriteRule: "logo.gif" -> "logo-orange.gif" # Na RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif" # http aanvragen :/ /example.com/images/header.png # De RewriteRule-invoer is "header.png" RewriteRule ^header.png$ /templates/rebranding/header.png # Na de RewriteRule: "header.png" -> "/ templates/rebranding /header.png" # Na RewriteBase: er verandert niets, dus het eindresultaat van de transformatie begint met "/". # Verzoek http://example.com/images/director.tiff # De RewriteRule-invoer is "director.tiff" # We gebruiken een externe relatieve omleiding RewriteRule ^director.tiff$ staff/manager/director.tiff # Na de RewriteRule: "director.tiff" -> "staff/manager/director.tiff" # + mod_rewrite onthoudt dat er een externe omleiding zal zijn # Na RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/ director.tiff" # mod_rewrite onthouden over de externe omleiding: # "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff

Meestal ontwikkelt zich na enige bekendheid met mod_rewrite de volgende gewoonte:

    voeg “RewriteBase /” toe aan elke .htaccess

    Alle omleidingen beginnen met een schuine streep: “RewriteRule news.php /index.php?act=news”. Dit helpt om artefacten uit RewriteBase te verwijderen, maar het is verkeerd om dit te doen. Nu we weten wat RewriteBase doet, kunnen we de volgende correcte regels formuleren:

RewriteBase moet overeenkomen met het pad van de siteroot naar .htaccess. U hoeft omleidingen alleen te starten met "/" als u het absolute pad van de hoofdmap van de site naar het bestand moet opgeven.

Wat gebeurt er als u RewriteBase niet opgeeft? Standaard maakt Apache het gelijk absoluut pad op het bestandssysteem vóór .htaccess (bijvoorbeeld /var/www/example.com/templates/). De onjuistheid van deze Apache-aanname blijkt duidelijk uit externe relatieve omleidingen:

# Verzoek http://example.com/index.php # DocumentRoot: /var/www/example.com/ # .htaccess bevindt zich in de root van de site en er is GEEN RewriteBase gespecificeerd. # Daarom is RewriteBase standaard gelijk aan het absolute pad naar.htaccess: /var/www/example.com/ # De invoer RewriteRule is "index.php" RewriteRule ^index.php main.php [R] # De uitvoer is "index.php" " -> "main.php" # mod_rewrite onthoudt dat een externe redirect nodig is # RewriteRule is op # mod_rewrite voert nog steeds RewriteBase uit, omdat het een standaardwaarde heeft. # Het blijkt: "main.php" -> "/var/www/example.com/main.php" # Hier onthoudt mod_rewrite dat er een externe omleiding was: # "/var/www/example.com/main. php" -> http://example.com/var/www/example.com/main.php # Het bleek helemaal niet wat ze in gedachten hadden.

Het verzoek heeft dus alle RewriteRules doorlopen, waarna er indien nodig een RewriteBase aan is toegevoegd. Moet Apache nu het bestand weergeven waarnaar het resulterende pad verwijst? Nee. Nu wordt het resulterende verzoek opnieuw verwerkt.

Hoe mod_rewrite werkt. Vlag [L]

mod_rewrite begint het verzoek keer op keer te verwerken totdat het niet meer verandert. En de vlag [L] kan het niet stoppen.

Bij het maken van min of meer complexe mod_rewrite-configuraties is het belangrijk om dat te begrijpen de wijziging van de query eindigt niet bij de laatste RewriteRule. Nadat het werkte laatste regel RewriteRule en RewriteBase zijn toegevoegd, mod_rewrite kijkt of het verzoek is gewijzigd of niet. Als het verzoek is gewijzigd, begint de verwerking opnieuw vanaf het begin.htaccess.

Apache doet dit omdat het verzoek tijdens het wijzigen mogelijk naar een andere map is omgeleid. Het kan zijn eigen .htaccess hebben die niet betrokken was bij de eerdere verwerking van verzoeken. Deze nieuwe .htaccess kan regels bevatten die de verwerking van het verzoek beïnvloeden - zowel mod_rewrite-regels als regels van andere modules. Om deze situatie correct af te handelen, moet Apache de gehele verwerkingslus opnieuw starten.

Wacht, maar er is een vlag [L], die stopt met het verwerken van het mod_rewrite-verzoek!

Niet echt. Vlag [L] stopt de huidige iteratie van de aanvraagverwerking. Als het verzoek echter werd gewijzigd door de RewriteRules die er nog steeds in slaagden het te verwerken, zal Apache de verzoekverwerkingscyclus opnieuw starten vanaf de eerste RewriteRule.

# Verzoek: http://example.com/a.html RewriteBase / RewriteRule ^a.html$ b.html [L] RewriteRule ^b.html$ a.html [L]

Het bovenstaande voorbeeld resulteert in een oneindige lus van omleidingen en "Internal Serverfout"op het einde. In dit voorbeeld is de oneindige lus duidelijk zichtbaar, maar in complexere configuraties moet u mogelijk in de regels duiken om te bepalen welke query's heen en weer lopen.

Om dergelijke situaties te voorkomen, wordt aanbevolen om de vlag [L] alleen te gebruiken als dat nodig is. De behoefte kan van twee soorten zijn: Wanneer een externe omleiding wordt gebruikt - of . Bij een externe redirect is verdere verwerking van het verzoek ongewenst (zie hieronder over de vlag [R]), en het is beter om ermee te stoppen. Wanneer er een lus in .htaccess zit die niet kan worden geëlimineerd, en de verwerking van het verzoek door mod_rewrite met geweld moet worden gestopt. In dit geval wordt een speciale constructie gebruikt - zie het einde van het artikel voor tips over dit onderwerp.

Maar het onderstaande voorbeeld zal niet in een lus verschijnen. Probeer te bepalen waarom en welk bestand uiteindelijk aan Apache wordt gegeven.

# Verzoek: http://example.com/a.html # Start.htaccess RewriteBase / RewriteRule ^a.html$ b.html RewriteRule ^b.html$ a.html # End.htaccess

Oplossing: Als gevolg van het uitvoeren van alle RewriteRules wordt de aanvraag zodanig gewijzigd dat het eindresultaat gelijk is aan het origineel. Apache ziet dit en verwerkt het verzoek niet opnieuw. Het a.html-bestand wordt geretourneerd.

Hoe mod_rewrite werkt. Vlag [R]

    Vlag [R] stopt de verwerking van verzoeken niet en retourneert onmiddellijk een externe omleiding. In plaats daarvan onthoudt het de noodzaak van een externe omleiding, en gaat de verwerking van het verzoek verder met de volgende RewriteRule. Het wordt aanbevolen om altijd met de vlag te gebruiken [L].

    Vlag [R] vertelt Apache dat het geen interne, maar een externe omleiding moet uitvoeren. Wat is het verschil tussen een externe omleiding en een interne omleiding? Een interne omleiding verandert eenvoudigweg het pad naar het bestand dat aan de gebruiker wordt gegeven, terwijl de gebruiker denkt dat hij het bestand ontvangt waar hij oorspronkelijk om heeft gevraagd. Bij een externe omleiding retourneert Apache de antwoordstatus 301 of 302 aan de gebruiker in plaats van de inhoud van het bestand en informeert de gebruiker over de link die de browser moet gebruiken om het bestand op te halen.

Het lijkt erop dat bij het verwerken van de vlag [R] Apache moet onmiddellijk stoppen met het verwerken van de RewriteRule en de externe omleiding naar de gebruiker retourneren. Laten we echter het fantastische voorbeeld uit de sectie Hoe RewriteRule werkt onthouden. Daarin hebben we eerst de vlag aangegeven [R], wat de noodzaak van een externe redirect aangeeft, waarna ze de link verder gingen wijzigen met de volgende RewriteRule.

Dit is precies hoe Apache werkt bij het opgeven van een externe omleiding. Het “merkt” eenvoudigweg bij zichzelf op dat het na het uitvoeren van alle regels nodig is om de status 302 terug te geven (standaard), maar gaat tegelijkertijd door met het uitvoeren van alle RewriteRules verderop in de lijst. We kunnen het verzoek blijven wijzigen als dat nodig is, het enige dat niet werkt is het weer intern maken van de omleiding.

Het is echter onwaarschijnlijk dat u dit op welke manier dan ook wilt wijzigen nadat u een externe omleiding heeft verzonden. Daarom wordt het aanbevolen bij het gebruik van de vlag [R] geef het samen met aan [L]:

# BlackJack is verhuisd naar een mooie naam RewriteRule ^bj/(.*) blackjack/$1 # Je kunt eenvoudigweg externe link RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]

In plaats van een vlag te gebruiken [R] U kunt eenvoudigweg een externe link opgeven. In dit geval zal Apache zelf raden dat het nodig is om een ​​externe omleiding te maken. Hier, zoals in het geval van het expliciet specificeren van de vlag [R], wordt aanbevolen om de vlag te gebruiken [L]. Als een externe omleiding naar dezelfde site leidt, is het beter om de vlag te gebruiken [R] zonder indicatie volledige koppeling(met andere woorden, gebruik een relatieve externe omleiding). Hierdoor wordt de regel onafhankelijk van de sitenaam. Indien een externe redirect naar een andere site leidt, kan dit niet anders dan door een volledige externe link op te geven.

Hoe mod_rewrite werkt. Specificatie van aanvraagparameters en vlag

Het wijzigen van de queryparameters in een RewriteRule verandert niets aan de rij waarop de volgende RewriteRule werkt. Als u de parameters wijzigt, verandert echter de %(QUERY_STRING) variabele waarmee RewriteCond kan werken.

Gebruikte terminologie: “parameters” - verzoekparameters, “argumenten” - RewriteRule-argumenten.

Met RewriteRule kunt u niet alleen het pad naar het bestand dat wordt verwerkt, maar ook de parameters wijzigen KRIJG verzoek die aan hem zal worden doorgegeven. Dit wordt vaak gebruikt om NC-verwerking over te dragen naar een generiek handlerscript, bijvoorbeeld: RewriteBase /

# Verzoek: http://example.com/news/2010/07/12/grand-opening.html # Invoer: "news/2010/07/12/grand-opening.html" RewriteRule ^news/(.* ) $ index.php?act=news&what=$1 # Na RewriteRule: "news/2010/07/12/grand-opening.html" -> "index.php" # %(QUERY_STRING): "" -> "act= news&what =2010/07/12/grote opening.html"

Op het moment dat de RewriteRule een vraagteken tegenkomt in zijn tweede argument, weet hij dat de parameters in het verzoek worden gewijzigd. Wat er gebeurt is dat RewriteRule de string waarmee het werkt vervangt door het deel van het tweede argument vóór het vraagteken. Houd er rekening mee dat de nieuwe aanvraagparameters niet in de tekenreeks terechtkomen waarop volgende RewriteRules zullen werken. Het deel van het tweede argument na het vraagteken komt terecht in de %(QUERY_STRING) variabele. Als er een vlag is opgegeven , worden de queryparameters toegevoegd aan het begin van %(QUERY_STRING). Als de vlag niet is opgegeven, wordt %(QUERY_STRING) volledig vervangen door de queryparameters uit de RewriteRule. Nog een paar voorbeelden:

RewriteBase / # Verzoek: http://example.com/news/2010/?page=2 # Voer RewriteRule in: "news/2010/" RewriteRule ^news/(.*)$ index.php?act=news&what=$1 # Na conversie: "news/2010/" -> "index.php" # Waarde %(QUERY_STRING): "page=2" -> "act=news&what=2010/" Hoogstwaarschijnlijk werkt de bovenstaande regel niet correct, omdat het is een verloren argumentpagina. Laten we dit oplossen: RewriteBase / # Request: http://example.com/news/2010/?page=2 # Input RewriteRule: "news/2010/" RewriteRule ^news/(.*)$ index.php?act= news&what=$1 # Na conversie: "news/2010/" -> "index.php" # Waarde %(QUERY_STRING): "page=2" -> "act=news&what=2010/&page=2"

Het is belangrijk om te begrijpen dat het wijzigen van de queryparameters de %(QUERY_STRING) verandert, die later in RewriteCond kan worden gebruikt. Hiermee moet rekening worden gehouden bij het schrijven van volgende regels die argumenten controleren.

Natuurlijk verandert het, omdat het verzoek voor herverwerking door Apache wordt verzonden!

Nee, %(QUERY_STRING) verandert onmiddellijk. Ik zal geen bewijs geven - er is al meer over parameters geschreven dan interessant is om te lezen :)

Wat kunt u doen om in RewriteCond precies die verzoekparameters in te checken die door de gebruiker zijn doorgegeven, en niet de parameters die zijn gewijzigd door RewriteRules? Zie de tips aan het einde van het artikel.

HerschrijfCond en prestaties

Eerst wordt de overeenkomst van het verzoek met de RewriteRule gecontroleerd, en pas daarna worden de aanvullende voorwaarden van RewriteCond gecontroleerd.

Er moeten een paar woorden worden gezegd over de volgorde waarin mod_rewrite richtlijnen uitvoert. Omdat .htaccess eerst met RewriteCond wordt geleverd en vervolgens met RewriteRule, lijkt het erop dat mod_rewrite eerst alle voorwaarden controleert en vervolgens begint met het uitvoeren van de RewriteRule.

Eigenlijk gebeurt alles andersom. Eerst controleert mod_rewrite of de huidige verzoekwaarde overeenkomt met de reguliere expressie RewriteRule, en alleen dan controleert het alle voorwaarden die zijn vermeld in RewriteCond.

Dus als u een reguliere expressie van twee pagina's in uw RewriteRule heeft en, denkend aan de prestaties, besluit u de uitvoering van deze regel te beperken tot extra RewriteConds, dan moet u weten dat niets zal werken. In dit geval is het beter om de RewriteRule-vlaggen [C] of [S] te gebruiken om meer over te slaan complexe regel, als eenvoudigere controles niet hielpen.

RewriteCond-variabelen en -vlaggen, andere RewriteRule-vlaggen, enz.

Lees de documentatie.

We maakten kennis met de werkingsprincipes van RewriteRule, RewriteBase, vlaggen [L], [R] En , en analyseerde ook het verzoekverwerkingsmechanisme binnen mod_rewrite. Het volgende bleef onaangetast: andere RewriteRule-vlaggen, RewriteCond- en RewriteMap-richtlijnen.

Gelukkig zijn deze richtlijnen en vlaggen niet mysterieus en werken ze precies zoals beschreven in de meeste tutorials. Om ze te begrijpen, hoeft u alleen maar de officiële documentatie te lezen. Allereerst raad ik aan om de lijst met variabelen te bestuderen die kunnen worden gecontroleerd in RewriteCond - %(QUERY_STING), %(THE_REQUEST), %(REMOTE_ADDR), %(HTTP_HOST), %(HTTP:header), etc.)

Verschil in hoe mod_rewrite werkt in de .htaccess-context en in de VirtualHost-context

In context mod_rewrite werkt precies het tegenovergestelde.

Zoals ik aan het begin van het artikel zei, heeft alles wat hierboven is beschreven betrekking op het gebruik van mod_rewrite in de .htaccess-context. Als mod_rewrite wordt gebruikt in , zal het anders werken: In de RewriteRule omvat het volledige verzoekpad, beginnend bij de eerste schuine streep en eindigend met het begin GET-parameters: "http://example.com/some/news/category/post.html?comments_page=3" → "/news/category/post.html". Deze regel begint altijd met /. Het tweede argument van RewriteRule moet ook beginnen met /, anders is het "Bad Request". RewriteBase heeft geen zin. Het passeren van de regels gebeurt slechts één keer. Vlag [L] voltooit daadwerkelijk het verwerken van alle regels die worden beschreven in , zonder verdere iteraties.

Reguliere expressies schrijven

Probeer reguliere expressies zo samen te stellen dat ze precies die query's definiëren die u wilt wijzigen, zodat de RewriteRule-regels niet per ongeluk voor een andere query werken. Bijvoorbeeld:

# Begin alle reguliere expressies met "^" (het begin van een regel) # en eindig met "$" (het einde van een regel): RewriteRule ^news.php$ index.php # Zelfs als dit niet nodig is - voor veelzijdigheid en een beter begrip van de configuratie: RewriteRule ^news/(.*)$ index.php # Als er alleen cijfers in het masker moeten worden opgenomen, specificeer dit dan expliciet. # Als sommige getallen constant zijn, specificeer ze dan expliciet. # Als er in de rest van het verzoek geen schuine strepen aanwezig kunnen zijn, beperk dan de aanwezigheid ervan. # Vergeet niet te ontsnappen "." (punten). # De volgende regel is gericht op verzoeken zoals http://example.com/news/2009/07/28/b-effect.html RewriteRule ^news/20(2)/(2)/(2)/[^/]+ \.html index.php

Echter, o reguliere expressies Er is een hele sectie op één bekende website.

Externe omleidingen wijzigen

Ondanks het feit dat je met mod_rewrite zelfs externe omleidingen kunt wijzigen met RewriteRule, tot in het protocol toe, raad ik je ten zeerste af dit te doen. In het artikel wordt het voorbeeld van het wijzigen van externe omleidingen alleen gebruikt om concepten als “links” en “bestanden” te verwijderen en duidelijker aan te tonen dat RewriteRule met een eenvoudige string werkt.

Ik denk niet dat de mod_rewrite-ontwikkelaars de bedoeling hadden dat iemand dit zou doen, dus allerlei artefacten zijn mogelijk. Doe dit niet alsjeblieft.

Hoe een oneindige lus te stoppen

Soms is de logica van omleidingen op een site zodanig dat mod_rewrite ze zonder speciale acties beschouwt als een eindeloze lus van omleidingen. Laten we het volgende voorbeeld nemen.

De site had een pagina /info.html. Dat heeft de SEO-specialist besloten zoekmachines zal deze pagina beter indexeren als deze /information.html heet en gevraagd wordt om een ​​externe redirect van info.html naar information.html. Om de een of andere reden kan de site-ontwikkelaar echter niet eenvoudigweg de naam info.html wijzigen in information.html en een omleiding maken - hij heeft de gegevens nodig die rechtstreeks vanuit het info.html-bestand worden verzonden. Hij schrijft volgende regel: # maak een externe redirect RewriteRule ^info.html information.html # maar geef op verzoek /information.html nog steeds info.html RewriteRule ^information.html info.html

... en komt een oneindige lus tegen. Elk /information.html-verzoek krijgt een externe omleiding terug naar /information.html.

Dit probleem kan op ten minste twee manieren worden opgelost. Eén ervan is al beschreven op Habré: je moet een omgevingsvariabele instellen en omleidingen stoppen op basis van de waarde ervan. De code ziet er als volgt uit:

RewriteCond %(ENV:REDIRECT_FINISH) !^$ RewriteRule ^ - [L] RewriteRule ^info.html$ informatie.html RewriteRule ^information.html$ info.html

Merk op dat mod_rewrite "REDIRECT_" toevoegt aan de naam van de variabele.

De tweede manier is om in THE_REQUEST te controleren wat precies door de gebruiker is aangevraagd:

# Externe omleiding gebeurt alleen als de gebruiker info.html heeft aangevraagd. # Als info.html het resultaat is van een interne omleiding, wordt de regel niet geactiveerd. RewriteCond %(THE_REQUEST) "^(GET|POST|HEAD) /info.html HTTP/+$" RewriteRule ^info.html$ informatie.html RewriteRule ^informatie.html$ info.html

Het analyseren van het oorspronkelijke gebruikersverzoek - het bestrijden van het vrijgeven van Apache-links

Bij het verwerken van een verzoek breidt Apache de URL-gecodeerde tekens uit het oorspronkelijke verzoek uit. In sommige gevallen is dit misschien niet wenselijk: de ontwikkelaar wil precies het originele, ongewijzigde gebruikersverzoek controleren. Dit kan gedaan worden door de %(THE_REQUEST) variabele in RewriteCond te controleren:

RewriteCond %(THE_REQUEST) ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$ RewriteRule ^(.*)$ index.php?tag=%1 [L]

Het komt voor dat gegevens vanaf de opdrachtregel naar een programma worden overgebracht wanneer het wordt aangeroepen. Dergelijke gegevens worden opdrachtregelargumenten genoemd. Het ziet er bijvoorbeeld zo uit:

./a.out test.txt ls -lt /home/peter/

Hier worden de programma's a.out (uit de huidige directory) en ls (uit dezelfde directory gespecificeerd in omgevingsvariabele PAD). Het eerste programma vanaf de opdrachtregel ontvangt één woord - test.txt, het tweede - twee: -lt en /home/peter/.

Als het programma in C is geschreven, wordt de besturing onmiddellijk overgedragen wanneer het wordt gestart belangrijkste functie() Daarom is het degene die de opdrachtregelargumenten ontvangt die zijn toegewezen aan de parametervariabelen.

Eerder hebben we de functie main() gedefinieerd alsof deze geen parameters nodig heeft en niets retourneert. In feite retourneert elke functie in de C-taal standaard (als er niets anders is gedefinieerd) een geheel getal. Hier kunt u zeker van zijn. Als je de code op deze manier schrijft:

main() ( printf ("Hallo \N");

retour 0;

)

  1. Er zal dan geen waarschuwing of fout optreden tijdens het compileren. Hetzelfde gebeurt als je int main() schrijft. Dit bewijst dat de functie standaard een geheel getal retourneert, en niet niets (void). Hoewel wat een functie retourneert altijd kan worden “overschreven”, bijvoorbeeld voidmain() of float main() ., waarmee het aantal woorden (elementen gescheiden door spaties) op de opdrachtregel wordt aangegeven wanneer deze wordt aangeroepen,
  2. verwijzing naar een array van strings, waar elke regel is apart woord vanaf de opdrachtregel.

Houd er rekening mee dat de programmanaam zelf ook telt. Als de oproep er bijvoorbeeld zo uitziet:

./a.uit 12 thema 2

Dan heeft het eerste argument van het programma de waarde 4, en de reeks strings wordt gedefinieerd als ("./a.out", "12", "theme", "2").

Let op de terminologie, er zijn slechts twee programmaargumenten (een getal en een array), maar zoveel opdrachtregelargumenten als u wilt. Opdrachtregelargumenten worden "geconverteerd" naar programmaargumenten (in hoofd()-functieargumenten).
Deze gegevens (nummer en aanwijzer) worden aan het programma doorgegeven, zelfs als het eenvoudigweg bij naam wordt aangeroepen zonder er iets aan door te geven: ./a.out. In dit geval heeft het eerste argument de waarde 1 en verwijst het tweede naar een array die uit slechts één regel bestaat ("./a.out").

Het feit dat gegevens in het programma worden doorgegeven, betekent niet dat de functie main() deze moet accepteren. Als de functie main() zonder parameters is gedefinieerd, is het niet mogelijk om toegang te krijgen tot de argumenten op de opdrachtregel. Hoewel niets je ervan weerhoudt ze door te geven. Er zal geen fout zijn.

Om toegang te krijgen tot de gegevens die aan het programma worden doorgegeven, moeten deze aan variabelen worden toegewezen. Omdat de argumenten onmiddellijk worden doorgegeven aan main() , zou de header er als volgt uit moeten zien:
hoofd (int n, char *arr)

De eerste variabele (n) bevat het aantal woorden en de tweede variabele bevat een verwijzing naar een array van strings. Vaak wordt de tweede parameter geschreven als **arr . Het is echter hetzelfde. Bedenk dat de array met strings zelf verwijzingen naar strings als elementen bevat. En we geven een verwijzing door naar het eerste element van de array naar de functie. Het blijkt dat we een aanwijzer doorgeven aan een aanwijzer, d.w.z. ** arr.

Oefening
Schrijf een programma als dit:

#erbij betrekken int main(int argc, char ** argv) ( int i; printf ("%d \N", argc);< argc; i++ ) puts (argv[ i] ) ; }

voor (i= 0; ik Het toont het aantal woorden op de opdrachtregel wanneer deze wordt aangeroepen en elk woord met nieuwe lijn

. Noem het zonder opdrachtregelargumenten en met argumenten.

In het programma gebruikten we de parametervariabelen argc en argv. Het is gebruikelijk om deze namen te gebruiken, maar in feite kunnen ze van alles zijn. Het is beter om je aan deze standaard te houden, zodat je programma's niet alleen voor jou, maar ook voor andere programmeurs begrijpelijker zijn.

Als je enige ervaring hebt met de GNU/Linux-opdrachtregel, weet je dat de meeste opdrachten schakelaars en argumenten hebben. Wanneer u bijvoorbeeld de inhoud van mappen bekijkt, kopieert of verplaatst, worden de bestandssysteemobjecten waarop de opdracht wordt uitgevoerd, opgegeven als argumenten. De kenmerken van de implementatie ervan worden bepaald met behulp van sleutels. In een team bijvoorbeeld

Cp -r ../les_1 ../les_101

cp is de opdrachtnaam, -r is de switch, en ../les_1 en ../les_101 zijn de opdrachtargumenten.

Over het algemeen worden bestandsadressen en "modifiers" (dit zijn sleutels) van het programma-uitvoeringsproces meestal overgedragen naar programma's wanneer ze worden gestart.

Laten we een programma schrijven dat wordt geopend opgegeven door de gebruiker op de opdrachtregel, bestanden om te schrijven of toe te voegen en schrijft (voegt) daar dezelfde informatie toe die de gebruiker invoert vanaf het toetsenbord tijdens de uitvoering van het programma:

#erbij betrekken #erbij betrekken main (int argc, char ** argv) ( int i, ch; BESTAND * f[ 5 ] ; if (argc< 3 || argc >7) (zet ( "Ongeldig aantal parameters"); retour 1;) if (strcmp (argv[ 1 ] , "-w" ) != 0 && strcmp (argv[ 1 ] , "-a" ) != 0 ) ( zet (< argc- 2 ; i++ ) { f[ i] = fopen (argv[ i+ 2 ] , argv[ 1 ] + 1 ) ; if (f[ i] == NULL) { printf ("De eerste parameter kan -w of -a zijn");< argc- 2 ; i++ ) putc (ch, f[ i] ) ; for (i= 0 ; i < argc- 2 ; i++ ) fclose (f[ i] ) ; return 0 ; }

retour 2;

  1. ) voor (i= 0; ik
  2. "Het bestand %s kan niet worden geopend\n "
  3. , argv[ i+ 2 ] ) ;
  4. retour 3; ) ) terwijl ((ch = getchar () ) != EOF) voor (i= 0; ik Uitleg voor de code: Er wordt een array van vijf bestandsaanwijzers gemaakt. Daarom kunt u niet meer dan vijf bestanden tegelijk openen. De bestandsaanwijzer van het eerste bestand wordt opgeslagen in arrayelement f, de tweede in f, enz., die beginnen vanaf het derde element van de argv-array. Dit is de reden waarom 2 aan i wordt toegevoegd om de elementen van de argv-array te krijgen, beginnend bij de derde. De expressie argc-2 geeft het aantal doorgegeven bestandsnamen aan; omdat argc slaat het totale aantal opdrachtregelargumenten op, waarvan de eerste twee geen bestandsnamen zijn.
  5. Met de uitdrukking argv+1 kunt u de subtekenreeks “w” (of “a”) uit de tekenreeks “-w” (of “-a”) “knippen”, omdat argv is in wezen een verwijzing naar het eerste element van de string. Door er één aan de aanwijzer toe te voegen, verplaatsen we deze naar het volgende element van de array.
  6. Als het bestand niet kan worden geopend, retourneert de functie fopen() NULL. In dit geval eindigt het programma.
  7. Elk teken dat de gebruiker op het toetsenbord invoert, wordt naar alle geopende bestanden geschreven.
  8. Aan het eind worden de dossiers gesloten.

Hoe vaak we PHP ook gebruiken, er duiken nog steeds functies op waar we nog nooit van hebben gehoord. Sommigen van hen zouden zeer nuttig voor ons zijn. Ik heb een kleine lijst gemaakt nuttige functies, wat in het arsenaal van elke PHP-programmeur zou moeten zitten.

1. Functies maken met een variabel aantal argumenten

Hoogstwaarschijnlijk weet je al dat PHP ons in staat stelt functies met optionele argumenten te maken. Nu zal ik een functie laten zien waarin het aantal argumenten van geval tot geval kan variëren.

Maar laten we eerst onthouden hoe we functies op de gebruikelijke manier creëren:

// functie met twee optionele parameters function foo($arg1 = "", $arg2 = "") ( echo "arg1: $arg1\n"; echo "arg2: $arg2\n"; ) foo("hello", "wereld"); /* levert het volgende op: arg1: hallo arg2: world */ foo(); /* levert het volgende op: arg1: arg2: */

Laten we nu eens kijken hoe u een functie kunt schrijven met een onbeperkt aantal argumenten. Om dit te doen, zal de func_get_args() methode gebruikt worden:

// specificeer geen argumenten functie foo() ( // retourneert een array van doorgegeven argumenten $args = func_get_args(); foreach ($args as $k => $v) ( echo "arg".($k+1) ." : $v\n"; ) ) foo(); /* zal niets uitvoeren */ foo("hello"); /* zal arg1 afdrukken: hallo */ foo("hallo", "wereld", "opnieuw"); /* zal arg1 afdrukken: hallo arg2: wereld arg3: opnieuw */

2. Gebruik Glob() om naar bestanden te zoeken

Vaak spreken de namen van functies voor zich. Hetzelfde kan niet gezegd worden voor de functie glob().

Zonder al te veel in detail te treden: de functionaliteit ervan is vergelijkbaar met de scandir()-methode. Het zorgt ervoor dat je kunt vinden vereiste bestand volgens het sjabloon:

// vind alle php-bestanden $files = glob("*.php"); print_r($bestanden); /* levert het volgende op: Array ( => phptest.php => pi.php => post_output.php => test.php) */

Om bestanden van verschillende typen te vinden, moet je als volgt schrijven:

// vind alle php- en txt-bestanden $files = glob("*.(php,txt)", GLOB_BRACE); print_r($bestanden); /* uitvoer: Array ( => phptest.php => pi.php => post_output.php => test.php => log.txt => test.txt) */

U kunt het pad ook in de sjabloon opgeven:

$files = glob("../images/a*.jpg"); print_r($bestanden); /* uitvoer: Array ( => ../images/apple.jpg => ../images/art.jpg) */

Om te ontvangen volledige pad gebruik voor het document de realpath() methode:

$files = glob("../images/a*.jpg"); // Pas de functie "realpath" toe op elk array-element $files = array_map("realpath",$files); print_r($bestanden); /* levert het volgende op: Array ( => C:\wamp\www\images\apple.jpg => C:\wamp\www\images\art.jpg) */

3. Informatie over het gebruikte geheugen

Als u bijhoudt hoeveel geheugen uw scripts verbruiken, zult u deze waarschijnlijk vaker optimaliseren.

In PHP is dat wel zo krachtig hulpmiddel bijhouden van geheugengebruik. IN verschillende onderdelen load-script kan afwijken. Om de gebruikte geheugenwaarde binnen te halen op dit moment, moeten we de methode memory_get_usage() gebruiken. Voor fixatie maximale hoeveelheid gebruikt geheugen gebruik memory_get_peak_usage()

Echo "Initiaal: ".memory_get_usage()." bytes \n"; /* Initieel: 361400 bytes */ // geef een kleine belasting voor ($i = 0; $i< 100000; $i++) { $array = md5($i); } // и ещё for ($i = 0; $i < 100000; $i++) { unset($array[$i]); } echo "Final: ".memory_get_usage()." bytes \n"; /* Final: 885912 bytes */ echo "Peak: ".memory_get_peak_usage()." bytes \n"; /* Peak: 13687072 bytes */

4. Verwerkerinformatie

Om dit te doen, moet je de getrusage() methode gebruiken. Maar houd er rekening mee dat deze functie niet werkt op Windows.

Print_r(getrusage()); /* drukt Array af ( => 0 => 0 => 2 => 3 => 12692 => 764 => 3864 => 94 => 0 => 1 => 67 => 4 => 0 => 0 => 0 => 6269 => 0) */

Het hierboven geschetste beeld zal duidelijk zijn voor degenen die ervaring hebben met systeembeheer. Voor alle anderen bieden we een transcriptie aan:

  • ru_oublock: aantal blokschrijfbewerkingen
  • ru_inblock: aantal blokleesbewerkingen
  • ru_msgsnd: aantal verzonden berichten
  • ru_msgrcv: aantal ontvangen berichten
  • ru_maxrss: maximale grootte niet-gepagineerde set
  • ru_ixrss: totale hoeveelheid gedeeld geheugen
  • ru_idrss: totaal volume aan niet-gedeelde gegevens
  • ru_minflt: aantal gebruikte geheugenpagina's
  • ru_majflt: aantal pagina-ontbrekende fouten
  • ru_nsignals: aantal ontvangen signalen
  • ru_nvcsw: aantal contextwisselingen door het proces
  • ru_nivcsw: aantal geforceerde contextwisselingen
  • ru_nswap: aantal schijftoegangen tijdens paging
  • ru_utime.tv_usec: bedrijfstijd in gebruikersmodus (microseconden)
  • ru_utime.tv_sec: bedrijfstijd in gebruikersmodus (seconden)
  • ru_stime.tv_usec: bedrijfstijd in bevoorrechte modus (microseconden)
  • ru_stime.tv_sec: bedrijfstijd in bevoorrechte modus (seconden)

Om erachter te komen welke bronnen van uw processor door het script worden gebruikt, heeft u de waarde 'user time' (gebruikerstijd) en 'system time' (privileged mode time) nodig. U kunt het resultaat zowel in seconden als in microseconden krijgen. Om het totale aantal seconden om te zetten in decimaal getal, moet je de waarde van microseconden delen door 1 miljoen en optellen bij de waarde van seconden.

Het is nogal verwarrend. Hier is een voorbeeld:

// rust gedurende 3 seconden slaap(3); $data = getrusage(); echo "Gebruikerstijd: ".

($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "Systeemtijd: ".

($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* prints Gebruikerstijd: 0,011552 Systeemtijd: 0 */

Hoewel het ongeveer 3 seconden duurde om het script uit te voeren, werd de processor niet zwaar belast. Het is een feit dat het script, wanneer het wordt aangeroepen (slaapstand), vrijwel geen processorbronnen verbruikt. Over het algemeen zijn er veel taken die een aanzienlijke hoeveelheid tijd in beslag nemen, maar waarbij de processor niet wordt gebruikt. Bijvoorbeeld wachten op schijfgerelateerde bewerkingen. U gebruikt dus niet altijd CPU-tijd in uw scripts.<10000000;$i++) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.424592 System time: 0.004204 */

Hier is nog een voorbeeld:

// loop 10 miljoen keer for($i=0;$i

Het script nam 1,4 seconden CPU-tijd in beslag. In dit geval zijn de systeemoproeptijden over het algemeen laag.< 3) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.088171 System time: 1.675315 */

De tijd in de bevoorrechte modus (Systeemtijd) is de tijd die de processor besteedt aan het uitvoeren van systeemverzoeken aan de kernel namens het programma. Voorbeeld:

$start = microtijd(waar); // bel microtime elke 3 seconden while(microtime(true) - $start

Nu is de systeemtijd veel meer besteed dan in het vorige voorbeeld. Allemaal dankzij de microtime()-methode, die systeembronnen gebruikt.

Houd er echter rekening mee dat de weergegeven tijd mogelijk niet nauwkeurig is. Op een gegeven moment worden processorbronnen ook door andere programma's gebruikt, wat tot een kleine fout kan leiden.

5. Magische constanten

// dit script is afhankelijk van de huidige bestandslocatie en // kan problemen veroorzaken als het vanuit verschillende mappen wordt gebruikt require_once("config/database.php"); // dit script zal geen problemen veroorzaken require_once(dirname(__FILE__) . "/config/database.php");

Gebruik __LINE__ bij het debuggen van scripts:

// code // ... my_debug("een foutopsporingsbericht", __LINE__); /* geeft regel 4 weer: een foutopsporingsbericht */ // meer code // ... my_debug("een ander foutopsporingsbericht", __LINE__); /* zal regel 11 afdrukken: nog een foutopsporingsbericht */ function my_debug($msg, $line) ( echo "Regel $line: $msg\n"; )

6. Unieke ID’s genereren

Er zijn momenten waarop u een unieke string moet genereren. Ik heb vaak gezien dat de functie md5() wordt gebruikt om dit probleem op te lossen:

// genereer een willekeurige tekenreeks echo md5(time() . mt_rand(1.1000000));

Maar in feite heeft PHP voor deze doeleinden een speciale functie uniqid().

// genereer een willekeurige string echo uniqid(); /* zal 4bd67c947233e afdrukken */ // nog een keer echo uniqid(); /* zal 4bd67c9472340 afdrukken */

Met het blote oog kun je zien dat de eerste symbolen, op zijn zachtst gezegd, vergelijkbaar zijn... Dit komt door het feit dat deze methode servertijd gebruikt om symbolen te genereren. Dit is zelfs handig, want... Alle gegenereerde waarden worden in alfabetische volgorde verkregen, waardoor ze snel kunnen worden gesorteerd.

Om de kans op een duplicaat te verkleinen, kunnen we een voorvoegsel toevoegen of een tweede parameter gebruiken (vergroot het aantal tekens):

// voorafgegaan door echo uniqid("foo_"); /* zal foo_4bd67d6cd8b8f afdrukken */ // met de tweede parameter echo uniqid("",true); /* zal 4bd67d6cd8b926.12135106 afdrukken */ // beide echo uniqid("bar_",true); /* zal bar_4bd67da367b650.43684647 uitvoeren */

Deze methode genereert strings die kleiner zijn dan md5, waardoor ruimte wordt bespaard.

7. Serialisatie

Heeft u ooit complexe gegevens in een database of bestand moeten opslaan? Om een ​​object naar een string te converteren, biedt PHP een speciale functie.

Over het algemeen zijn er twee van deze methoden: serialize() en unserialize()

// complexe array $myvar = array("hallo", 42, array(1,"twee"), "appel"); // converteren naar string $string = serialize($myvar); echo $string; /* zal a:4:(i:0;s:5:"hallo";i:1;i:42;i:2;a:2:(i:0;i:1;i:1; s :3:"two";)i:3;s:5:"apple";) */ // haal de originele waarde op $newvar = unserialize($string); print_r($newvar); /* zal Array uitvoeren ( => hallo => 42 => Array ( => 1 => twee) => appel) */

Dit is hoe deze functies werken. Vanwege de snelle groei in populariteit van JSON zijn er echter twee methoden json_encode() en json_decode() toegevoegd aan PHP 5.2. Hun werk is vergelijkbaar met serialize():

// complexe array $myvar = array("hallo", 42, array(1,"twee"), "appel"); // converteren naar string $string = json_encode($myvar); echo $string; /* zal ["hello",42,"apple"] afdrukken */ // herstel de oorspronkelijke waarde $newvar = json_decode($string); print_r($newvar); /* drukt Array af ( => hallo => 42 => Array ( => 1 => twee) => appel) */

Deze optie is compacter en compatibel met andere talen zoals JavaScript. Bij het werken met zeer complexe objecten kan er echter gegevensverlies optreden.

8. Snaarcompressie

Als we het over compressie hebben, denk ik meteen aan: archiveer bestanden V ZIP-formaat. PHP biedt de mogelijkheid om lange strings te comprimeren zonder bestanden.

Het volgende voorbeeld laat zien hoe de functies gzcompress() en gzuncompress() werken:

$string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut elit id mi ultricies adipiscing. Nulla facilisi. Praesent pulvinar, sapien vel feugiat vestibulum, nulla dui pretium orci, non ultricies elit lacus quis ante. Lorem ipsum dolor sit amet Het lichaam van het lichaam wordt in de loop van de tijd enorm verwend eu niet enim. "; $gecomprimeerd = gzcompress($string); echo "Originele grootte: ". strlen($string).."\n"; /* zal de originele grootte weergeven: 800 */ echo "Gecomprimeerde grootte: ". strlen($gecomprimeerd).."\n"; /* geeft de gecomprimeerde grootte weer: 418 */ // return $original = gzuncompress($gecomprimeerd);

We kunnen het tekstvolume met 50% verminderen. Voor dezelfde doeleinden kunt u de methoden gzencode() en gzdecode() gebruiken, die een ander compressie-algoritme gebruiken.

9. Voer uit voordat u afsluit

PHP heeft een register_shutdown_function()-functie waarmee u code kunt uitvoeren voordat u het script afsluit.

Stel dat u wat informatie wilt weten... Looptijd van het script:

// haal de starttijd op $start_time = microtime(true); // sommige bewerkingen // ... // geven de looptijd-echo "execution taken: " weer.

(microtime(true) - $start_time).

"seconden.";

Op het eerste gezicht lijkt dit misschien een triviale taak. Voor deze doeleinden kunt u de code aan het einde van het bestand plaatsen. Als de functie exit() echter ergens eerder wordt geactiveerd, zal deze code nooit werken. Het zal ook niet werken als er een fout op de pagina staat of als de gebruiker het laden van de pagina onderbreekt (door op de overeenkomstige knop in zijn browser te klikken);

Bij gebruik van de methode register_shutdown_function() wordt de code in ieder geval uitgevoerd:

$start_time = microtijd(waar); register_shutdown_function("mijn_shutdown"); function my_shutdown() ( global $start_time; echo "uitvoering duurde: ". (microtime(true) - $start_time). " seconden."; )

Conclusie

PHP is een hele planeet die ons voortdurend blijft verbazen met zijn inhoud. Wat vind je van deze functies?

Bij het maken van een consoletoepassing in de programmeertaal C++ wordt automatisch een regel gemaakt die hier sterk op lijkt: Int main(int argc, char* argv) // main() functieparameters Deze regel is de kop belangrijkste functie main() , worden de parameters argс en argv tussen haakjes gedeclareerd. Dus als het programma wordt gestart via opdrachtregel, dan is het mogelijk om wat informatie naar dit programma over te dragen; daarom bestaan ​​de parameters argc en argv. De parameter argc is van het type gegevens int en bevat het aantal parameters dat aan de hoofdfunctie is doorgegeven. Bovendien is argc altijd minstens 1, zelfs als we geen informatie doorgeven, aangezien de eerste parameter de naam van de functie is. De parameter argv is een array van verwijzingen naar tekenreeksen. Alleen stringgegevens kunnen via de opdrachtregel worden doorgegeven. Pointers en strings zijn twee grote onderwerpen waarvoor aparte secties zijn gemaakt. Het is dus via de parameter argv dat alle informatie wordt verzonden. Laten we een programma ontwikkelen dat we via de opdrachtregel zullen starten

Windows-tekenreeks en geef haar wat informatie.<< argv<

// argc_argv.cpp: definieert het toegangspunt voor de consoletoepassing. #include "stdafx.h" #include

naamruimte std gebruiken; int main(int argc, char* argv) ( if (argc >

// code Code::Blokken // Dev-C++-code<< argv<

Nadat we fouten in het programma hebben opgelost, opent u de Windows-opdrachtregel en sleept u het uitvoerbare bestand van ons programma naar het opdrachtregelvenster. Het volledige pad naar het programma wordt weergegeven op de opdrachtregel (maar u kunt het pad naar het programma handmatig invoeren). ), waarna u kunt klikken BINNENKOMEN en het programma zal starten (zie figuur 1).

Figuur 1 - Belangrijkste functieparameters

Omdat we het programma gewoon hebben uitgevoerd en er geen argumenten aan hebben doorgegeven, verscheen het bericht Geen argumenten. Figuur 2 toont de lancering van hetzelfde programma via de opdrachtregel, maar geeft het Open-argument door.

Figuur 2 - Belangrijkste functieparameters

Het argument is het woord Open, zoals je kunt zien in de figuur, dit woord verscheen op het scherm. U kunt meerdere parameters tegelijk doorgeven, gescheiden door een komma. Als u een parameter moet doorgeven die uit meerdere woorden bestaat, moeten deze tussen dubbele aanhalingstekens worden geplaatst en worden deze woorden als één parameter beschouwd. De figuur toont bijvoorbeeld de lancering van een programma, waarbij een argument wordt doorgegeven dat uit twee woorden bestaat: het werkt.

Figuur 3 - Belangrijkste functieparameters

En als je de aanhalingstekens verwijdert. Dan zullen we alleen het woord Het zien. Als u niet van plan bent om informatie door te geven tijdens het uitvoeren van het programma, kunt u de argumenten in de functie main() verwijderen, en kunt u ook de namen van deze argumenten wijzigen. Soms worden wijzigingen aan de parameters argc en argv aangetroffen, maar dit hangt allemaal af van het type applicatie dat wordt gemaakt of van de ontwikkelomgeving.