E-post: salg@linmag.no



9.9.2010 - 13:49
 • Nyheter
 • Om Linux
 • Linuxskolen
 • Spørrespalte
 • Vitsespalte
 • LINUXmagasinet
 • Spill
 • WEBSHOP
 • Diskusjonsforum
 • Linker
 • For annonsører
 • English
 • Om oss
developer.ez.no
www.online4u.no

0

Linuxskolen


Linuxskolen er en serie innføringsartikler som ble startet opp i LINUXmagasinet nr 5/2001.

Lag din egen proxy
Her vil jeg vise dere et lite triks for å vise websider som kommer fra tjenere som ikke er synlig fra internett. Jeg hadde bruk for en slik løsning da jeg ville vise dynamiske websider fra en tjener som lå i et NAT-et nett, og så hadde jeg alt en webtjener i nettet som var synlig fra internett. Løsningen baserer seg på Apache og en av to standardmoduler, PHP og kjennskap til HTTP-protokollen.

Jeg har ADSL fra NextGenTel (NGT) og en enkel Netopia-router som NAT-er nettet mitt. I den har jeg mulighet til å videresende porter inn i det NAT-ede nettet mitt. Hjemme hos oss har alle bokser navn fra Harry Potter, og tjeneren vår heter dumbledore (10.0.0.2) og arbeidsstasjonen min heter harry (10.0.0.4). Begge kjører Debian GNU/Linux og Apache, og jeg har satt opp Netopiaen slik at forespørsler på port 80 mot vår tildelte IP-adresse fra NGT videresendes til dumbledore. Jeg har jobbet med webutvikling direkte på harry, og har hatt behov for å kunne vise dette på nett uten å ta ned tjenestene som kjører på dumbledore. Dette endte opp med at jeg skrev en slags proxy i PHP og la denne på dumbledore. I dette eksemplet kommer jeg til å bruke phpsysinfo som den dynamiske tjenesten

apache-magi
Jeg hadde forholdsvis god kunnskap om HTTP-protokollen, samt god kjennskap til moduler i Apache. Jeg hadde en idé om å bruke Apaches Error-Document for å fange opp forsøk på nedlasting av dokumenter som ikke befinner seg på webtjeneren. ErrorDocument-konfigurasjonen i Apache lar deg overstyre hvilken webside som skal håndtere slike feil. Jeg valgte å skrive et PHP-skript for denne oppgaven. Målet var å finne ut hvilken fil som opprinnelig skulle lastes ned, åpne en forbindelse til harry (min arbeidsstasjon) og hente dokumentet derifra i stedet. Etter å ha finpusset skriptet og prøvd og feilet litt, kom det en dag hvor jeg hadde tatt i bruk denne løsningen mot en løsning som benyttet seg av skjemaopplasting med metoden POST. Det fungerte selvfølgelig ikke. ErrorDocument redirigerer kun åpningen av en fil, og får dermed ikke med seg verdiene som måtte være fylt ut i skjemaet, da disse blir sendt som en del av forespørselshodet i den opprinnelige forespørselen. Løsningen for å bruke det med POST-løsninger ble en annen modul i Apache, nemlig Rewrite-modulen. Vanligvis er ikke denne aktivert i en standardinstallasjon, og krever derfor at mod_rewrite blir lastet ved start av Apache.

konfigurasjon
Som standard på Debian, ligger webdokumentene i /var/www. Jeg har alt en phpsysinfo-katalog der, så jeg lager meg en /var/www/phpsysinfo2/ . Denne vil være synlig som http://dumbledore/phpsysinfo2/ . Jeg skal ikke bruke POST i denne løsningen, så det holder å bruke ErrorDocument i en .htaccess-fil.
Dette står i min .htaccess-fil:
ErrorDocument 404 /var/www/phpsysinfo2/index.php

Det første argumentet er hvilken type feil som skal håndteres, det andre hvilken fil som skal håndtere feilen. Jeg vil ta hånd om feil av typen 404, som er koden for at filen du forsøker å hente ikke eksisterer.
Får du feil fra Apache, må du sjekke i Apache-konfigurasjonen at du har lov til å overstyre FileInfo for den katalogen du bruker.

Vi vil trenge kunnskap om regulære uttrykk (mønstergjenkjenning) og åpning av en forbindelse til en annen maskin og hvordan skrive og lese fra denne forbindelsen.
Jeg har gjenbrukt denne koden en del ganger, og har satt opp fire variable (linje 32-35) for konfigurasjon. Det eneste jeg derfor trenger å fikse, er .htaccess og de fire variable, og løsningen virker (forhåpentligvis).
Localparter katalogstien etter hostnavnet i en URL, i mitt eksempel med http://dumbledore/phpsysinfo2/ er dette altså /phpsysinfo2/. Remote host er enkelt, det er harry, og harry har IP-adressen 10.0.0.2. Remote port er standard web-port, som er 80. Ser du på /etc/services på din Linux-maskin, får du oversikt over hvilke porter som er tildelt forskjellige tjenester. Remote part er katalogstien på harry, i dette tilfellet phpsysinfo. Oversatt til en form vi kjenner fra før, er dette det samme som http://10.0.0.2/phpsysinfo/ .

regulære uttrykk
Regulære uttrykk er en måte å beskrive mønster i tekststrenger. Det finnes tykke bøker om emnet, og det er ikke plass til å gå i detalj her. PHP støtter to typer regulære uttrykk (regexp); POSIX- og Perl-syntaks. Jeg er en gammel Perl-skalle, og foretrekker Perls måte å beskrive mønster på.
Det første vi trenger i vårt skript, er å vite hvilket dokument som opprinnelig ble forsøkt hentet. PHP har en innebygd variabel som heter $REQUEST_URI som inneholder katalogstien til dokumentet som ble forsøkt hentet. I linje 41-43 gjør vi så litt regexp-magi. Som du ser, er det to preg_replace inni hverandre. Det som skjer er at vi fjerner den lokale katalogstien slik at vi sitter igjen med en katalogsti vi kan hente fra den andre tjeneren.
La oss starte med den innerste; preg_replace(«///», «/», $localpart). Preg_replace tar minst 3 argumenter. Det første er en regexp, det andre er hva denne regexp skal erstattes med, og det tredje er hvilken tekststreng som det skal utføres på. Alle Perl-regexper starter og slutter med tegnet /. La oss dekode det regulære uttrykket “///”. Vi vet nå at den første og siste /-en avgrenser mønsteret, vi sitter dermed igjen med /. brukes i Perl-regexp for å angi spesielle tegn eller for å maskere andre spesialtegn som brukes i mønstrene. Mønsteret i regexpen vil dermed lete etter alle forekomster av tegnet /. Det andre argumentet sier vi at vi skal erstatte dette med /. Hva betyr da dette? Som vi så i forbindelse med regexpen, er et spesialtegn for blant annet å maskere spesialtegn. blir dermed en ekte . Med norske ord på første og andre argument blir dette: Finn alle / og erstatt dem med /. Dette skal vi gjøre på $localpart. Variabelen $localpart kan inneholde /-er og derfor må vi sørge for at disse er erstattet med / for å kunne bruke dette videre i den ytterste preg_replacen.
Når vi nå vet at den innerste preg_replacen gir oss /phpsysinfo2/ kan vi begynne å se på det ytterste regulære uttrykket. Hvis tenker oss at den innerste preg_replace er kjørt og at vi erstatter denne med det den returnerer, står nå preg_replace(«/^».”/phpsysinfo2/”.”/”, “”, $REQUEST_URI)
Javel, det så jo mest ut som noen hadde satt seg på tastaturet. For å slå sammen teksttrenger i PHP, bruker man tegnet . (punktum). Det første argumentet blir da /^/phpsysinfo2//. Hvis et regulært Perl-uttrykk begynner med /^ betyr denne ^-en at vi skal lete i begynnelsen av strengen (det finnes en tilsvarende $/ for å lete i slutten av en streng). Da ble det jo ikke vanskelig; vi skal lete etter strenger som begynner med /phpsysinfo2/. Deretter skal vi erstatte dette med “”. Dette er jo det samme som ingenting, og det vil si at vi sletter dette. Det hele skal bli utført på tekststrengen som er lagret i $REQUEST_URI.
Phpsysinfohar en del grafikk-elementer som viser forbrukt diskplass osv. Et eksempel på en slik kan være /phpsysinfo2/templates/classic/images/bar_middle.gif. Når vi har kjørt dette igjennom våre to preg_replacer, sitter vi igjen med templates/classic/images/bar_middle.gif som er det vi skal hente fra vår skjulte webtjener.

simuler en webleser
Da har vi nok informasjon til å håndtere åpning av alle dokumenter under http://dumbledore/phpsysinfo2/ . Nå er det på tide å snakke med harry og hente dokumentene derfra. I linje 46 åpner vi en forbindelse med funksjonen fsockopen. Legg merke til min bruk av @ foran funksjonen. Denne @-en “svelger” eventuelle feilmeldinger fra funksjonen som følger etter. I og med jeg har bruk en if(..) rundt, vil en eventuell feil medføre at dette ikke er sant, og PHP vil hoppe til den tilsvarende } else { blokken og kjøre den. Dette for å lage en mer brukervennlig feilmelding til brukeren.
Neste bolk i koden er om cookies. Enkelt forklart er en cookie en bitteliten informasjonskapsel som webtjeneren sender i meldingshodet
til en webklient. Webklienten vil så sende informa-sjonskapselen tilbake til webtjeneren ved neste forespørsel. Vi må sørge for at alle innkommende cookies fra klienten blir sendt videre til den skjulte webtjeneren. Fra PHP får vi variabelen $_COOKIE som inneholder alle cookie-informasjonskapslene webleseren sendte. $_COOKIE er en hashtable og i en hashtable lagrer man informasjon med en gitt nøkkel. Et eksempel: $bil er en hashtable. I $bil lagrer vi informasjonen om bilens farge med nøkkelen farge; $bil[“farge”] = “rød”. Så kan vi lagre antall dører på bilen; $bil[“dører”] = 3. etc. ved å bruke foreach, løper vi igjennom alle nøkkelverdi-parene. Meldingshodet for en cookie, er av formen “Cookie: key1=value1; key2=value2 ... keyn=valuen;”. Ved første nøkkelpar starter vi variablen med å sette Cookie og nøkkelen og verdien, for de påfølgende legger vi dem til variablen ved å bruke .= (som betyr legg til denne på slutten av strengen).

get eller post
I dette eksemplet er det ikke behov for POST, da phpsysinfo ikke benytte POST. Vi tar likevel med for å kunne gjenbruke koden der hvor det er behov for det. PHP har en hash som heter $_SERVER som inneholder en rekke variable fra webtjeneren det kjører under (Apache i vårt tilfelle). Fra denne hashen sjekker vi om REQUEST_METHOD er POST, for å så bygge opp en korrekt POST-forespørsel til vår skjulte webtjener. På linjene 59 til 65 gjør vi nesten samme triks som vi brukte til cookiene. Vi løper igjennom hashtabellen $_POST (som er innebygget i PHP) og bygger opp en variabel på formen “key1=valye1&key2=value2..keyn=valuen”. Deretter bygger vi opp en forespørsel for en POST i linjene 66 til 72. En POST-forespørsel skal begynne med en linje som starter med POST og katalogsti samt hvilken HTTP-protokoll. Jeg har valgt HTTP versjon 1.1 for bl.a. få støtte for virtuelle webtjenere. Dernest er det hvilken virtuell host man ønsker å hente katalogstien fra. Så en linje med hva slags forespørsel dette er og en linje med hvor lang datastreng webtjeneren kan forvente seg. Her benytter vi strlen for å finne lengden av dataene. Når man benytter HTTP versjon 1.1 bør man ha med en linje hvor man forteller at forbindelsen skal stenges når dataoverføringen er over. Hvis man ikke har det, vil lese-løkken som kommer senere vente på at forbindelsen tidsavbrytes, og sidene vil ta lang tid å åpne. Så legger vi til cookiene vi genererte tidligere. Et meldingshode avsluttes med en tom linje, derfor har vi nn før vi sender over dataene som skal postes. Det finnes andre, men sjeldent brukte metoder enn GET og POST. I dette skriptet nøyer oss med å si at om det ikke var POST, så er det GET. På linjene 74 til 77 ser vi at meldingshodet til en GET er mye enklere enn POST. Vi trenger en GET-linje, en Host-linje, en linje for å fortelle at forbindelsen skal avsluttes og en linje med cookie.
gi meg et dokument
Vi bruker metoden fputs for å sende forespørselen til den skjulte webtjeneren. Dette er en generell funksjon for strømmer av data, filer, prosesser eller forbindelser over TCP/IP. Det skal ha to argumenter; hvilken strøm det skal skrives til og det som skal skrives.
Et svar fra en webtjener består av to deler. Som bruker ser vi vanligvis bare den siste. Den første delen er et meldingshode som inneholder blant annet cookies, hvor langt dokumentet er, hva slags dokument det er, hvilken tegnsettkoding og mye mer. Meldingshodet og meldingskroppen er skilt med en tom linje.
Vi kan dermed lese fra datastrømmen fra den skjulte webtjeneren helt til den første linjen som er tom kommer. Dette gjør vi på linje 82. I koden står det while($line = chop(@fgets($sp,1024))). Dette betyr at så lenge vi kan tilordne en linje til variabelen $line skal vi kjøre bolken med data. I PHP er en tilordning av en tom streng det samme som feil, altså vil vi lese til den tomme linjen kommer. Nå er ikke linjen helt tom, det er et spesialtegn som sier neste linje, ved å bruke chop() fjerner vi det siste tegnet fra en linje, dermed vil en linje som kun inneholder et ny-linje-tegn blir en tom streng. Lese fra datastrømmen gjør vi så med fgets() som på samme måte som fputs er en generell datastrøm-funksjon. Første argument er identifikator til strømmen og det andre er hvor mye data vi skal lese. Alt dette er meldingshodet og noe av dette bør vi videresende til webleseren, og vi bør sjekke for feil fra den skjulte webtjeneren. Dette gjør vi med regexp i bolken på linje 84 til 91.
I koden står det if(preg_match(«/^HTTP/1.d ([4-5]0d) (.*)$/», $line, $foo)). Preg_match har vi ikke brukt ennå, så dette krever litt forklaring. Den tar 2 eller 3 argumenter; det første er mønsteret, det andre er hvilken tekststreng vi skal teste mot og det siste er et valgfritt variabelnavn for å samle eventuelle utdrag fra mønsteret i. La oss se på mønsteret i det regulære uttrykket; /^HTTP/1.d ([4-5]0d) (.*)$/. Tidligere lærte vi at / avgrenser uttrykket og at /^ betyr i begynnelsen og $/ betyr i slutten av tekststrengen. Dette mønsteret skal altså passe på en hel linje. Først forventer vi HTTP så en / og en 1. Vi vet alt at maskerer det påfølgende tegnet, men vi visste kanskje ikke at . var et spesialtegn. I Perl-regexp betyr et enkelt . det samme som “ett eller annet som er et tegn langt”. d har vi heller ikke sett. Dette er et spesialuttrykk som betyr et tall (d for engelsk digit). På norsk forventer vi altså en streng som begynner men HTTP/1.'tall'. I dag er tallet enten 0 eller 1 avhengig av hvilken HTTP-protokoll webtjeneren benytter.
I Perl-regexp kan man gruppere mønster ved å sette parenteser rundt “(...)”. Disse gruppene vil da bli tatt vare på og kan benyttes til eventuell videre manipulering. I PHP tar man vare på disse i den variablen man definerer i det tredje argumentet. La oss komme tilbake til dette og først se på det som står i den første parentesen. [4-5]0d. [..] er en måte å si at her forventer man tegn av disse typene. 4-5 betyr tallrekken fra 4 til og med 5. Hadde det stått 3-7 hadde vi ønsket et tall fra tallrekken 3 til og med 7. Deretter sier vi det skal være en null (0) og til slutt et vilkårlig tall (d). Vi ønsker altså å treffe tallene fra 400 til 409 og 500 til 509. Dette er feilkoder som er definert i HTTP-protokollen og sier noe om at dokumentet ikke er tilgjengelig.
Til slutt er det nok en parentesgruppe. I denne ønsker vi å treffe .*. Vi så at . betyr et vilkårlig tegn, mens * betyr 0 eller flere forekomster av foregående enhet. .* betyr altså 0 eller flere tegn. Hadde det stått d* hadde vi forventet 0 eller flere tall f.eks. Litt avhengig av hva slags webtjener den skjulte er, vil det komme en forklarende tekst på feilkoden. Denne vil vi også ta vare på (derfor parenteser rundt).
Hvis denne testen slår til, har vi altså en feilsituasjon fra den andre webtjeneren. Denne bør vi varsle brukeren om. Først bruker vi header-funksjonen i PHP til å sende den samme feiltypen til klienten. Denne finner vi igjen som det første parentesen. $foo er et array og for de som er kjent med arrays er det kanskje overraskende at man ikke bruker det første elementet, 0, som indeks. På det første elementet ligger ikke den første grupperingen, men hele linjen som passet til mønsteret. Dermed er vår feilkode å finne i $foo[1]. Vi skriver ut feilkoden, slår sammen med den forespurte katalogstien og så til slutt den eventuelle forklaringen fra webtjeneren. Deretter lukker vi datastrømmen med fclose() og avslutter skriptet med exit();.
På linjene 98 til 109 er det et oppbrutt regulært uttrykk for å fange opp noen av de eventuelle hode-meldingene for så å sende de videre til webleseren. Vi fanger opp statuskode med HTTP, datatype med Content-Type, sist modifisert-dato med Last-Modified, lengde med Content-Length, eventuelle redirigeringer med Location, cookies med Set-Cookie, mellomlagringstyring med Pragma og Cache-Control, når dokumentet ikke er gyldig lenger med Expires, skal forbindelsen avsluttes med Connection og tilslutt en kode som sier at datastrømmen kommer i biter med Transfer-Encoding.
Om vi tar bare to av kodene fra det regulære uttrykket, vil det se ut slik; preg_match(«/^(?:HTTP/1.d|Content-Type): .+$/”, $line). Nok en gang er det hele tekststrengen vi vil finne. Noe av det nye denne gangen er ?: inne i den første parentesen. Dette betyr at denne parentes-grupperingen ikke skal tas vare på. De to kodene er skilt med |-tegnet, altså vil vi treffe det ene eller det andre. I den opprinnelige koden, kan vi se at hver kode avsluttes med et |-tegn for å si at det er flere muligheter som kan være sanne. : betyr et : så det er det ikke noe
spesielt med. I forrige regexp så vi på .*, det betydde 0 eller flere tegn av vilkårlig type. .+ betyr nesten det samme, bortsett fra at + er minst 1 eller flere. Vi vil finne disse kodene i begynnelsen av linjen og de skal ha et påfølgende :-tegn et mellomrom og minst ett tegn til. Får vi treff her, sender vi bare disse videre med den innebygde PHP-funksjonen header().
Når denne løkken har gått igjennom meldingshodet, er det bare å sende dokumentdataene til webleseren.

fpassthru er nok en generell datastrømsfunksjon. Den tar en peker til en datastrøm og sender den resterende strømmen til klienten. Etter at den er ferdig skal datastrømmen være tom, og vi kan lukke den.
Aller sist i koden, ligger bolken som kjøres om man ikke får kontakt med den skjulte webtjeneren. Den er ikke mye å forklare. Ønsker man å legge til mer informasjon om hvor man f.eks. skal henvende seg ved feil, er det bare å utøve egen kreativitet her.

har dette svakheter?
Ja, det er en del svakheter med dette trikset. For det første er det ikke spesielt effektivt om det er veldig stor pågang til disse dataene. Det hadde f.eks kanskje vært lurt å lagre en midlertidig kopi for å slippe å overføre så mye data. Dette er slik ekte webproxyer oppfører seg.

En annen ting er at det ikke er tatt høyde for andre metoder enn GET og POST. Dessuten har vi ingen sjekking på at skriving og lesing går korrekt. Jeg har valgt å sette @ foran alle datastrømsfunksjoner, men ikke tatt høyde for at enkelte kan feile. Skulle det derfor oppstå en situasjon hvor man får opp en forbindelse men ikke klarer å skrive, vil dette skriptet returnere tomt dokument uten en forklaring på hvorfor.

hva har vi lært?
Vi har sett på en del regulære uttrykk for å erstatte (preg_replace) og slette mønstre i tekststrenger og for å sjekke at en tekststreng inneholder ønsket resultat (preg_match). Vi har lært en del om hvordan meldingshoder i HTTP fungerer og vi har lært en del om å skrive og lese fra datastrømmer. Forhåpentligvis har du blitt inspirert til å se på dette og kanskje lage andre løsninger ved bruk av ErrorDocument. Eksempler på hva du kan gjøre er å hente dataene fra en database i stedet for en annen webtjener, utvide skriptet til å mellomlagre dataene i en temporær katalog og sikkert mange andre smarte ting. Vil du lære mer om Apache, HTTP og PHP, kan du surfe deg inn på noen av disse lenkene:
Apache - http://httpd.apache.org/
HTTP - http://www.w3.org/Protocols/
PHP – http://www.php.net/


kildekode
  1	<?php
  2	/* 
  3	 * A redirector script
  4	 *
  5	 * Copyright©2003 - Rune Nordbøe Skillingstad <rune@skillingstad.no>
  6	 * Licensed under GPL, see http://www.gnu.org/licenses/gpl.txt 
  7	 * 
  8	 * How to use: 
  9	 * * Install this script as <localpart>/index.php
 10	 * * Edit the configuration to suit your needs
 11	 * * Add a <localpart>/.htaccess, containing one of these settings:
 12	 *   Simple error handling (POST will not work)
 13	 * -[.htaccess]——————————————————————————-
 14	 *   ErrorDocument 404 <localpart>/index.php
 15	 * ————————————————————————————————-
 16	 *
 17	 *   To get POST key/value-pairs redirected, use mod_rewrite instead
 18	 * -[.htaccess]——————————————————————————-
 19	 *   <IfModule mod_rewrite.c> 
 20	 *     RewriteEngine On 
 21	 *     RewriteBase /
 22	 *     RewriteCond %{REQUEST_FILENAME} !-f 
 23	 *     RewriteCond %{REQUEST_FILENAME} !-d 
 24	 *     RewriteRule (.*) <localpart>/index.php 
 25	 *   </IfModule> 
 26	 * ————————————————————————————————-
 27	 */
 28	
 29	/*
 30	 * Configuration
 31	 */
 32	$localpart  = “/phpsysinfo2/”;              # Localpart on local host
 33	$remotehost = “10.0.0.4”;                   # The remote host
 34	$remoteport = 80;                           # The remote port
 35	$remotepart = “/phpsysinfo/”;               # Localpart on remote host
 36	
 37	/*
 38	 * The magic
 39	 */
 40	// Extract the part behind localpart
 41	$document = preg_replace(“/^”.preg_replace(“///”, “/”, $localpart).”/”,
 42				 “”, 
 43				 $REQUEST_URI);
 44	
 45	// Open a TCP connection to remote host at given port
 46	if($sp = @fsockopen($remotehost, $remoteport)) {
 47	  // Concatenate cookies
 48	  foreach($_COOKIE as $key => $value) {
 49	    if(!$cookie) {
 50	      $cookie = “Cookie: $key=$value;”;
 51	    } else {
 52	      $cookie .= “ $key=$value”;
 53	    }    
 54	  }
 55	  // Method POST is a bit different. 
 56	  // Requires mod_rewrite to work
 57	  if($_SERVER[“REQUEST_METHOD”] == “POST”) {
 58	    // Concatenate the POST key/value pairs
 59	    foreach($_POST as $key => $value) {
 60	      if(!$data) {
 61		$data = “$key=$value”;
 62	      } else {
 63		$data = “&$key=$value”;
 64	      }
 65	    }
 66	    $request = “POST “ . $remotepart . $document . “ HTTP/1.1n”.
 67	      “Host: $remotehostn” . 
 68	      “Content-type: application/x-www-form-urlencodedn”.
 69	      “Content-length: “ . strlen($data) . “n”.
 70	      “Connection: closen”.  // Close the stream at once 
 71	      “$cookienn”.
 72	      $data;
 73	  } else { // Make it easy, if not method PUT, we use GET
 74	    $request = “GET “ . $remotepart . $document . “ HTTP/1.1n”.
 75	      “Host: $remotehostn”.
 76	      “Connection: closen”.  // Close the stream at once
 77	      “$cookienn”;
 78	  }
 79	  // Send request
 80	  @fputs($sp, $request);
 81	  // Parse the header from the request
 82	  while($line = chop(@fgets($sp,1024))) {
 83	    // We might get an error - forward this, warn and exit 
 84	    if(preg_match(“/^HTTP/1.d ([4-5]0d) (.*)$/”, $line, $foo)) {
 85	      header($line);
 86	      echo “<strong>” . $foo[1] . “</strong> “ . 
 87             $REQUEST_URI . “ “ .
 88             $foo[2];
 89	      @fclose($sp);
 90	      exit(); 
 91	    }
 92	    // Use the same headers (to some level) as the original
 93	    if(preg_match(“/^(?:”.
 94			  “HTTP/1.d|”.      // HTTP status; 400/500 already traped
 95			  “Content-Type|”.     // text/html and so on
 96			  “Last-Modified|”.    // often overridden in dynamic content
 97			  “Content-Length|”.   // length is good for most browsers
 98			  “Location|”.         // redirects should work
 99			  “Set-Cookie|”.       // cookies (eg. Sessions)
100			  “Pragma|”.           // controlls cache in HTTP/1.0
101			  “Cache-Control|”.    // controlls cache in HTTP/1.1
102			  “Expires|”.          // when do a page expire from cache 
103			  “Connection|”.       // tell browser to close?
104			  “Transfer-Encoding”. // HTTP/1.1 might respond with chucks
105			  “): .+$/”,
106			  $line));
107	    {
108	      header($line);
109	    }
110	  }
111	  @fpassthru($sp); // pass body to end client
112	  @fclose($sp);
113	} else {
114	  // We were not able to open a connection to remote host
115	  echo “<strong>Internet is full - go away!</strong>n”;
116	  echo “$host not reachable<br />”;
117	}


om forfatteren
Rune Nordbøe Skillingstad ,rune@skillingstad.no, jobber som avdelingsingeniør ved Det Medisinske Fakultet, NTNU i Trondheim. Han er en av redaktør-ene i Linuxguiden.no, utvikler i Skolelinux og for tiden styremedlem i Linux i Skolen.



0








0 0