InfoNET Список использованых источников Авторам

Подборка 1
  • Как на PHP организовать коллекцию ссылок без базы данных?
  • Руководство по РНР 3.0
  • Программирование на PHP. Галерея фотографий (картинок)
  • Голосование на РНР!
  • Безопасный и удобный поиск на PHP
  • Что такое PHP-Nuke или Web-портал за 15 минут
  • PHP.Первые шаги. Действительно легкая смена дизайна
  • Люди, используйте PHP! Часть первая
  • Работа с файлами при помощи PHP
  • HotMail своими руками, или Что может PH
  • Листинги
    • IMAP Mailbox Header List
    • function sendmail
    • class pop3_class
    • function validateEmail
    • Отправка писем с аттачами/html-страницами, через сокет, учет кодировок win koi dos


Содержание InfoNET Авторам

Список использованых источников

Автор: Арсен Кириллов, г.Львов 2001, softm@ukr.net
Статья: Как на PHP организовать коллекцию ссылок без базы данных?

Всероссийский Клуб Вебмастеров, www.webclub.ru
Статьи: Руководство по РНР 3.0

Автор: Тотоев Александр, totoeval@mtu-net.ru, www.czar.ru, www.nova-wings.ru
Статья: Программирование на PHP. Галерея фотографий (картинок)

Автор: Андрей Кухарчик, июнь 2001, virtualbrest@tut.by, http://virtual.bresttelecom.by
Статья:Голосование на РНР!

Автор:Дмитрий Лебедев, dnl@au.ru, Клуб PHP-разработчиков
Статья:Безопасный и удобный поиск на PHP

Автор:GUGO, http://4User.ru/
Статья:Что такое PHP-Nuke или Web-портал за 15 минут

Автор: Евгений Молодкин, johny_webmaster@nm.ru, http://www.party.hut.ru/
Статья:Люди, используйте PHP! Часть первая

Автор:Виктор Хименко
Статья:HotMail своими руками, или Что может PH

Листинги:
IMAP Mailbox Header List. Administrator, webmaster@php.codebase.org
class pop3_class. Manuel Lemos, mlemos@acm.org
function validateEmail. Jon S. Stevens, jon@clearink.com
Отправка писем с аттачами/html-страницами, через сокет, учет кодировок win koi dos. Antonio, из фоpума Клуба PHP-разработчиков

Один шаг назад


Содержание InfoNET Список использованых источников Авторам

<?php

     /*
      * Name: IMAP Mailbox Header List
      * By:   Administrator - webmaster@php.codebase.org
      * This example is a quick and dirty routine for connecting to an IMAP server and outputting a plain-HTML table of the message headers.  It handles all IMAP-related errors gracefully.
      * Tested on version 3.0.5 of PHP
      *
      * http://php.codebase.org
      * http://www.php.net
      *
      * $Id
      */

?>
<?php

   /* set login variables */
  $imap_server_address =  "imap.mail.server";
  $imap_server_port    =  "143";              /* default IMAP port */
  $imap_server_mailbox =  "INBOX";
  $imap_username       =  "user";
  $imap_password       =  "pass";

   /* open server stream */
  $imap_stream = imap_open( "{$imap_server_address:$imap_server_port}$imap_server_mailbox",$imap_username,$imap_password);

   /* test stream */
  if ($imap_stream == 0)
  {
    echo  "Error connecting to IMAP server.  Bad IMAP stream.";
    exit();
  }
  else
  {
     /* get current mailbox info object */
    $mailbox_info = imap_mailboxmsginfo($imap_stream);

     /* test mailbox message info */
    if ($mailbox_info == 0)
    {
      echo  "Error getting mailbox info.";
      exit();
    }
    else
    {
       /* output table header */
      echo  "<table border=1>\n";

       /* loop through message headers */
      for ($i = 1; $i <= $mailbox_info->Nmsgs; $i++)
      {
         /* set message object */
        $message_header = imap_header($imap_stream, $i);

         /* build data for table row */
        $table_number     = $message_header->Msgno;
        $temp_msgno       = trim($message_header->Msgno);
         /* test for "real name", otherwise print email address */
        $from_object = $message_header->from[0];
        if ($from_object->personal ==  "")
        {
          $table_from = htmlspecialchars(substr($from_object->mailbox .  "@" . strtolower($from_object->host), 0, 30));
        }
        else
        {
          $table_from = htmlspecialchars($from_object->personal);
        }

        $table_date     = date( "D,", $message_header->udate) .  "&nbsp;" . date( "m/j", $message_header->udate);
        $table_size     = $message_header->Size;
        $table_subject  = (chop($message_header->subject ==  "")) ?  "[No Subject]" : $message_header->subject;

         /* set recent / unread messages to bold */
        if (($message_header->Unseen ==  "U") || ($message_header->Recent ==  "N"))
        {
          $table_from    =  "<b>" . $table_from .  "</b>";
          $table_date    =  "<b>" . $table_date .  "</b>";
          $table_size    =  "<b>" . $table_size .  "</b>";
          $table_number  =  "<b>" . $table_number .  "</b>";
          $table_subject =  "<b>" . $table_subject .  "</b>";
        }

         /* echo table row */
    echo  "<tr>\n";
    echo  "<td>$table_number</td>";
    echo  "<td>$table_from</td>";
    echo  "<td>$table_date</td>";
    echo  "<td>$table_size</td>";
    echo  "<td>$table_subject</td>";
    echo  "</tr>\n";

      }  /* for: message table */

       /* conditionally include message table empty message */
      if ($mailbox_info->Nmsgs == 0)
      {
    echo  "<td colspan=5>No Messages</td>";
      }

       /* output table footer */
      echo  "</table>\n";

    }  /* else: nomailboxinfo */

     /* close IMAP stream */
    $imap_close = imap_close($imap_stream);

  }  /* else: nostream */

?>


<?
function sendmail($from_name,$from_address,$to_address,$subject,$message,$additional_headers='')
{
   $MSG =  "Return-Path: <$from_address>\n";

   $MSG .= "To: $to_address\n";

   $from = $from_address;
   if (!empty($from_name))
     $from = "$from_name <$from>";
   $MSG .= "From: $from\n";

   $ZONE = Date('Z');
   $SIGN = '+';
   if ($ZONE > 0) $SIGN = '-';
   $ZONE = abs($ZONE);
   $MSG .= 'Date: '.Date('D, d M Y H:i:s ').$SIGN.sprintf('%02d%02d',floor($ZONE/3600),floor(($ZONE%3600)/60))."\n";

   if (!empty($subject))
     $MSG .= "Subject: $subject\n";

   $MSG .= "$additional_headers\n";

   $MSG .= "\n";
   $MSG .= $message;

   $fp = popen('/usr/lib/sendmail -t','w');
   $num = fputs($fp,$MSG);
   pclose($fp);

   return $num;
}
?>


<?

/*
* Copyright (C) 1998, Manuel Lemos (mlemos@acm.org)
*
* Permission to use and modify this software and its
* documentation for any purpose other than its incorporation
* into a commercial product is hereby granted without fee,
* as long as the author is notified that this piece of software
* is being used in other applications.
* Permission to copy and distribute this software and its
* documentation only for non-commercial use is also granted
* without fee, provided, however, that the above copyright
* notice appear in all copies, that both that copyright notice
* and this permission notice appear in supporting documentation.
* The author makes no representations about the suitability
* of this software for any purpose.  It is provided ``as is'',
* without express or implied warranty.
*/

/* put this class definition in a file named pop3.php */

class pop3_class
{
 var $hostname="";
 var $port=110;

 /* Private variables - DO NOT ACCESS */

 var $connection=0;
 var $state="DISCONNECTED";
 var $greeting="";
 var $must_update=0;

 /* Private methods - DO NOT CALL */

 Function GetLine()
 {
  for($line="";;)
  {
   if(feof($this->connection))
    return(0);
   $line.=fgets($this->connection,100);
   $length=strlen($line);
   if($length>=2
   && substr($line,$length-2,2)=="\r\n")
    return(substr($line,0,$length-2));
  }
 }

 Function PutLine($line)
 {
  return(fputs($this->connection,"$line\r\n"));
 }

 Function OpenConnection()
 {
  if($this->hostname=="")
   return("2 it was not specified a valid hostname");
  switch(($this->connection=fsockopen($this->hostname,$this->port)))
  {
   case -3:
    return("-3 socket could not be created");
   case -4:
    return("-4 dns lookup on hostname \"$hostname\" failed");
   case -5:
    return("-5 connection refused or timed out");
   case -6:
    return("-6 fdopen() call failed");
   case -7:
    return("-7 setvbuf() call failed");
   default:
    return("");
  }
 }

 Function CloseConnection()
 {
  if($this->connection!=0)
  {
   fclose($this->connection);
   $this->connection=0;
  }
 }

 /* Public methods */

 /* Open method - set the object variable $hostname to the POP3 server address. */

 Function Open()
 {
  if($this->state!="DISCONNECTED")
   return("1 a connection is already opened");
  if(($error=$this->OpenConnection())!="")
   return($error);
  $this->greeting=$this->GetLine();
  if(GetType($this->greeting)!="string"
  || strtok($this->greeting," ")!="+OK")
  {
   $this->CloseConnection();
   return("3 POP3 server greeting was not found");
  }
  $this->greeting=strtok("\r\n");
  $this->must_update=0;
  $this->state="AUTHORIZATION";
  return("");
 }

 /* Close method - this method must be called at least if there are any
     messages to be deleted */

 Function Close()
 {
  if($this->state=="DISCONNECTED")
   return("no connection was opened");
  if($this->must_update)
  {
   if($this->PutLine("QUIT")==0)
    return("Could not send the QUIT command");
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not get quit command response");
   if(strtok($response," ")!="+OK")
    return("Could not quit the connection: ".strtok("\r\n"));
  }
  $this->CloseConnection();
  $this->state="DISCONNECTED";
  return("");
 }

 /* Login method - pass the user name and password of POP account.  Set
     $apop to 1 or 0 wether you want to login using APOP method or not.  */

 Function Login($user,$password,$apop)
 {
  if($this->state!="AUTHORIZATION")
   return("connection is not in AUTHORIZATION state");
  if($apop)
  {
   if($this->PutLine("APOP $user ".md5($this->greeting.$password))==0)
    return("Could not send the APOP command");
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not get APOP login command response");
   if(strtok($response," ")!="+OK")
    return("APOP login failed: ".strtok("\r\n"));
  }
  else
  {
   if($this->PutLine("USER $user")==0)
    return("Could not send the USER command");
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not get user login entry response");
   if(strtok($response," ")!="+OK")
    return("User error: ".strtok("\r\n"));
   if($this->PutLine("PASS $password")==0)
    return("Could not send the PASS command");
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not get login password entry response");
   if(strtok($response," ")!="+OK")
    return("Password error: ".strtok("\r\n"));
  }
  $this->state="TRANSACTION";
  return("");
 }

 /* Statistics method - pass references to variables to hold the number of
     messages in the mail box and the size that they take in bytes.  */

 Function Statistics($messages,$size)
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($this->PutLine("STAT")==0)
   return("Could not send the STAT command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not get the statistics command response");
  if(strtok($response," ")!="+OK")
   return("Could not get the statistics: ".strtok("\r\n"));
  $messages=strtok(" ");
  $size=strtok(" ");
  return("");
 }

 /* ListMessages method - the $message argument indicates the number of a
     message to be listed.  If you specify an empty string it will list all
     messages in the mail box.  The $unique_id flag indicates if you want
     to list the each message unique identifier, otherwise it will
     return the size of each message listed.  If you list all messages the
     result will be returned in an array. */

 Function ListMessages($message,$unique_id)
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($unique_id)
   $list_command="UIDL";
  else
   $list_command="LIST";
  if($this->PutLine("$list_command $message")==0)
   return("Could not send the $list_command command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not get message list command response");
  if(strtok($response," ")!="+OK")
   return("Could not get the message listing: ".strtok("\r\n"));
  if($message=="")
  {
   for($messages=array();;)
   {
    $response=$this->GetLine();
    if(GetType($response)!="string")
     return("Could not get message list response");
    if($response==".")
     break;
    $message=intval(strtok($response," "));
    if($unique_id)
     $messages[$message]=strtok(" ");
    else
     $messages[$message]=intval(strtok(" "));
   }
   return($messages);
  }
  else
  {
   $message=intval(strtok(" "));
   return(intval(strtok(" ")));
  }
 }

 /* RetrieveMessage method - the $message argument indicates the number of
     a message to be listed.  Pass a reference variables that will hold the
     arrays of the $header and $body lines.  The $lines argument tells how
     many lines of the message are to be retrieved.  Pass a negative number
     if you want to retrieve the whole message. */

 Function RetrieveMessage($message,$headers,$body,$lines)
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($lines<0)
  {
   $command="RETR";
   $arguments="$message";
  }
  else
  {
   $command="TOP";
   $arguments="$message $lines";
  }
  if($this->PutLine("$command $arguments")==0)
   return("Could not send the $command command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not get message retrieval command response");
  if(strtok($response," ")!="+OK")
   return("Could not retrieve the message: ".strtok("\r\n"));
  for($headers=$body=array(),$line=0;;$line++)
  {
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not retrieve the message");
   switch($response)
   {
    case ".":
     return("");
    case "":
     break 2;
    default:
     if(substr($response,0,1)==".")
      $response=substr($response,1,strlen($response)-1);
     break;
   }
   $headers[$line]=$response;
  }
  for($line=0;;$line++)
  {
   $response=$this->GetLine();
   if(GetType($response)!="string")
    return("Could not retrieve the message");
   switch($response)
   {
    case ".":
     return("");
    default:
     if(substr($response,0,1)==".")
      $response=substr($response,1,strlen($response)-1);
     break;
   }
   $body[$line]=$response;
  }
  return("");
 }

 /* DeleteMessage method - the $message argument indicates the number of
     a message to be marked as deleted.  Messages will only be effectively
     deleted upon a successful call to the Close method. */

 Function DeleteMessage($message)
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($this->PutLine("DELE $message")==0)
   return("Could not send the DELE command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not get message delete command response");
  if(strtok($response," ")!="+OK")
   return("Could not delete the message: ".strtok("\r\n"));
  $this->must_update=1;
  return("");
 }

 /* ResetDeletedMessages method - Reset the list of marked to be deleted
     messages.  No messages will be marked to be deleted upon a successful
     call to this method.  */

 Function ResetDeletedMessages()
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($this->PutLine("RSET")==0)
   return("Could not send the RSET command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not get reset deleted messages command response");
  if(strtok($response," ")!="+OK")
   return("Could not reset deleted messages: ".strtok("\r\n"));
  $this->must_update=0;
  return("");
 }

 /* IssueNOOP method - Just pings the server to prevent it auto-close the
     connection after an idle timeout (tipically 10 minutes).  Not very
     useful for most likely uses of this class.  It's just here for
     protocol support completeness.  */

 Function IssueNOOP()
 {
  if($this->state!="TRANSACTION")
   return("connection is not in TRANSACTION state");
  if($this->PutLine("NOOP")==0)
   return("Could not send the NOOP command");
  $response=$this->GetLine();
  if(GetType($response)!="string")
   return("Could not NOOP command response");
  if(strtok($response," ")!="+OK")
   return("Could not issue the NOOP command: ".strtok("\r\n"));
  return("");
 }
};

/* ---- pop3.php3 class file ends here. ---- */

/*  --- example file ---*/
?>
<HTML>
<HEAD>
<TITLE>POP3 PHP class test</TITLE>
</HEAD>
<BODY>
<?
 include("pop3.php3");

 $user="mlemos";
 $password="password";
 $apop=0;
 $pop3_connection=new pop3_class;
 $pop3_connection->hostname="localhost";
 if(($error=$pop3_connection->Open())=="")
 {
  echo "<PRE>Connected to the POP3 server &quot;$pop3_connection->hostname&quot;.</PRE>\n";
  if(($error=$pop3_connection->Login($user,$password,$apop))=="")
  {
   echo "<PRE>User &quot;$user&quot; logged in.</PRE>\n";
   if(($error=$pop3_connection->Statistics(&$messages,&$size))=="")
   {
    echo "<PRE>There are $messages messages in the mail box with a total of $size bytes.</PRE>\n";
    $result=$pop3_connection->ListMessages("",0);
    if(GetType($result)=="array")
    {
     for(Reset($result),$message=0;$message<count($result);Next($result),$message++)
      echo "<PRE>Message ",Key($result)," - ",$result[Key($result)]," bytes.</PRE>\n";
     $result=$pop3_connection->ListMessages("",1);
     if(GetType($result)=="array")
     {
      for(Reset($result),$message=0;$message<count($result);Next($result),$message++)
       echo "<PRE>Message ",Key($result),", Unique ID - \"",$result[Key($result)],"\"</PRE>\n";
      if($messages>0)
      {
       if(($error=$pop3_connection->RetrieveMessage(1,&$headers,&$body,2))=="")
       {
        echo "<PRE>Message 1:\n---Message headers starts below---</PRE>\n";
        for($line=0;$line<count($headers);$line++)
         echo "<PRE>",HtmlSpecialChars($headers[$line]),"</PRE>\n";
        echo "<PRE>---Message headers ends above---\n---Message body starts below---</PRE>\n";
        for($line=0;$line<count($body);$line++)
         echo "<PRE>",HtmlSpecialChars($body[$line]),"</PRE>\n";
        echo "<PRE>---Message body ends above---</PRE>\n";
        if(($error=$pop3_connection->DeleteMessage(1))=="")
        {
         echo "<PRE>Marked message 1 for deletion.</PRE>\n";
         if(($error=$pop3_connection->ResetDeletedMessages())=="")
         {
          echo "<PRE>Resetted the list of messages to be deleted.</PRE>\n";
         }
        }
       }
      }
      if($error==""
      && ($error=$pop3_connection->Close())=="")
 echo "<PRE>Disconnected from the POP3 server &quot;$pop3_connection->hostname&quot;.</PRE>\n";
}
     else
      $error=$result;
    }
  else
  $error=$result;
   }
  }
 }
 if($error!="")
  echo "<H2>Error: ",HtmlSpecialChars($error),"</H2>";
?>

</BODY>
</HTML>


<?php

/*
By: Jon S. Stevens jon@clearink.com
Copyright 1998-1999 Jon S. Stevens, Clear Ink
This code has all the normal disclaimers.
It is free for any use, just keep the credits intact.
*/

function validateEmail ( $email )
{
    global $SERVER_NAME;
    $return = array ( false, "" );
    list ( $user, $domain )  = split ( "@", $email, 2 );
    $tld = $domain;
    if ( checkdnsrr ( $tld, "MX" ) )
    {
        if ( getmxrr ( $tld, $mxhosts, $weight ) )
        {
            for ( $i = 0; $i < count ( $mxhosts ); $i++ )
            {
                $fp = fsockopen ( $mxhosts[$i], 25 );
                if ( $fp )
                {
                    $s = 0;
                    $c = 0;
                    $out = "";
                    set_socket_blocking ( $fp, false );
                    do
                    {
                        $out = fgets ( $fp, 2500 );
                        if ( ereg ( "^220", $out ) )
                        {
                            $s = 0;
                            $out = "";
                            $c++;
                        }
                        else if ( ( $c > 0 ) && ( $out == "" ) )
                        { break; }
                        else
                        { $s++;    }
                        if ( $s == 9999 ) { break; }

                    } while ( $out == "" );
                    set_socket_blocking ( $fp, true );

                    fputs ( $fp, "HELO $SERVER_NAME\n" );
                    $output = fgets ( $fp, 2000 );
                    fputs ( $fp, "MAIL FROM: <info@" . $tld . ">\n" );
                    $output = fgets ( $fp, 2000 );
                    fputs ( $fp, "RCPT TO: <$email>\n" );
                    $output = fgets ( $fp, 2000 );
                    if ( ereg ( "^250", $output ) )
                    {
                        $return[0] = true;
                    }
                    else
                    {
                        $return[0] = false;
                        $return[1] = $output;
                    }
                    fputs ( $fp, "QUIT\n" );
                    fclose( $fp );

                    if ( $return[0] == true )
                    { break; }
                }
            }
        }
    }
    return $return;
}
?>


Отправка писем с аттачами/html-страницами, через сокет, учет кодировок win koi dos

(c) Antonio, из фоpума phpclub.net

Как послать письмо в HTML виде? Присоедините к письму аттач с названием message.html и письмо превратиться в HTML-письмо!

<?
//Функции. Можно вынести в дpугой файл.
class html_mime_mail {
  var $headers;
  var $multipart;
  var $mime;
  var $html;
  var $parts = array();
function html_mime_mail($headers="") {
    $this->headers=$headers;
}
function add_html($html="") {
    $this->html.=$html;
}
function build_html($orig_boundary,$kod) {
    $this->multipart.="--$orig_boundary\n";
    if ($kod=='w' || $kod=='win' || $kod=='windows-1251') $kod='windows-1251';
    else $kod='koi8-r';
    $this->multipart.="Content-Type: text/html; charset=$kod\n";
    $this->multipart.="BCC: del@ipo.spb.ru\n";
    $this->multipart.="Content-Transfer-Encoding: Quot-Printed\n\n";
    $this->multipart.="$this->html\n\n";
}
function add_attachment($path="", $name = "", $c_type="application/octet-stream") {
    if (!file_exists($path.$name)) {
      print "File $path.$name dosn't exist.";
      return;
    }
    $fp=fopen($path.$name,"r");
    if (!$fp) {
      print "File $path.$name coudn't be read.";
      return;
    }
    $file=fread($fp, filesize($path.$name));
    fclose($fp);
    $this->parts[]=array("body"=>$file, "name"=>$name,"c_type"=>$c_type);
}
function build_part($i) {
    $message_part="";
    $message_part.="Content-Type: ".$this->parts[$i]["c_type"];
    if ($this->parts[$i]["name"]!="")
       $message_part.="; name = \"".$this->parts[$i]["name"]."\"\n";
    else
       $message_part.="\n";
    $message_part.="Content-Transfer-Encoding: base64\n";
    $message_part.="Content-Disposition: attachment; filename = \"".
       $this->parts[$i]["name"]."\"\n\n";
    $message_part.=chunk_split(base64_encode($this->parts[$i]["body"]))."\n";
    return $message_part;
}
function build_message($kod) {
    $boundary="=_".md5(uniqid(time()));
    $this->headers.="MIME-Version: 1.0\n";
    $this->headers.="Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
    $this->multipart="";
    $this->multipart.="This is a MIME encoded message.\n\n";
    $this->build_html($boundary,$kod);
    for ($i=(count($this->parts)-1); $i>=0; $i--)
      $this->multipart.="--$boundary\n".$this->build_part($i);
    $this->mime = "$this->multipart--$boundary--\n";
}
function send($server, $to, $from, $subject="", $headers="") {
    $headers="To: $to\nFrom: $from\nSubject: $subject\nX-Mailer: The Mouse!\n$headers";
    $fp = fsockopen($server, 25, &$errno, &$errstr, 30);
    if (!$fp)
    die("Server $server. Connection failed: $errno, $errstr");
    fputs($fp,"HELO $server\n");
    fputs($fp,"MAIL FROM: $from\n");
    fputs($fp,"RCPT TO: $to\n");
    fputs($fp,"DATA\n");
    fputs($fp,$this->headers);
    if (strlen($headers))
    fputs($fp,"$headers\n");
    fputs($fp,$this->mime);
    fputs($fp,"\n.\nQUIT\n");
    while(!feof($fp))
    $resp.=fgets($fp,1024);
    fclose($fp);
  }
}
// *************************************************************************
//   В качестве аттача пpисоединяем html-письмо (открывается автоматически).
//   Второй аттач - некоторый файл из каталога.
//   Вот так вызывать все то, что написано выше:
// *************************************************************************
  $mail=new html_mime_mail();
  $mail->add_html("<html><body><center><h2>Пpивет!<br><br>".
                  "<br>Посылаю двоичный файл [/bin/ls] ...".
                  "</h2></center></body></html>");
  $mail->add_attachment("/bin/","ls");
  $mail->build_message('win'); // если не "win", то кодиpовка koi8
  $mail->send('ПОЧТОВЫЙ_ХОСТ_ВАШЕГО_ПРОВАЙДЕРА',
              'КОМУ_(E-MAIL)',
              'ОТ_КОГО_(E-MAIL)',
              'ТЕМА ПИСЬМА');
// После прихода письма качаем по ФТП оригинальный /bin/ls и сравниваем с
// импортированным из письма:
//
//    X:\temp>fc /b ls ls2
//    Сравнение файлов ls и LS2
//    FC: различия не найдены
//
// Внимание! Если у вас нет файла /bin/ls, то просто закомментируйте строку
// $mail->add_attachment("/bin/","ls"), чтобы программа не пыталась присоединить
// к письму неcуществующие файлы.
?>

Комментаpии по пpосьбам тpудящихся. Будут добавляться до тех поp, пока всем все не станет понятно.

> ...объяснить поподробнее, то что написано
> на http://php.spb.ru/php/mail.html.
> Т.е. я не понял, вся та информация, она
> располагается все на одной странице или то,....

Пpогpамма состоит из 2х частей.

1 - необходимые функции
2 - как написать письмо с аттачем. Аттач -- это HTML-письмо, содеpжащее слово "пpивет"

> И второе: ("<html><body><center><h2>пpивет</h2>
> </center></body></html>") - это есть само тело послание,
> которое придет на mail ???

Да, это и есть аттач. Их может быть несколько. > .. но у меня возникли кое-какие еще вопросы:
> "почтовый хост" - в этом случае прописывается тот адрес, где
> реально находиться почтовый ящик (т.е. в большинстве
> случаев у провайдера) или нет

Нет. Этот параметр не имеет никакого отношения к каким-либо почтовым ящикам... Если вы не можете запонить это поле, то не занимайтесь программированием вообще.

1. Открываем свою почтовую программу (для тех, кто не понял: Outlook, Thebat или др)
2. Смотрим, что указано в поле "исходящий (SMTP) сервер"
3. Пишем в параметре "ХОСТ" эти данные (без угловых скобок)

Пример: smtp.peterlink.ru (если я являюсь клиентом Петерлинка, что дает мне право пользоваться сервером почты). Любой человек как-то пишет письма в Инет. Это "как-то" он делает через почтовый сервер своего провайдера.

> "кому" - ???
> "от кого" - ???
> "тема" - ???
Нет, пожалуй эти поля комментировать не будем... Хотя:
Кому - пример: vasya@pupkin.ru
От кого - пример (от меня): dmitry@php...ru
Тема - пример: ...
Нет, все же лучше не комментировать...


Арсен Кириллов г.Львов 2001 г.softm@ukr.net

Как на PHP организовать коллекцию ссылок без базы данных?

Для того чтобы создать и успешно работать с коллекцией ссылок на вашем сайте вполне достаточно "голого" php. Как обеспечить постраничный вывод информации , как подсчитывать количество переходов по ссылкам и как сортировать ссылки я и покажу в данной статье.

Текстовая база данных (ТБД) - в этой статье это группа текстовых файлов
Таблица ТБД текстовый файл в котором одной записи данных отвечает одна строка.
Поле ТБД- разделенный символами ограничителями текст. В качестве символов ограничителей могут выступать любые символы, при условии что они не будут встречаться в информации. Я использовал для этой цели вертикальную черту. Однако формат ТБД может быть произвольным так как обработка будет выполняться с помощью регулярных выражений, что и дает такую гибкость в выборе формата.
Для того чтобы вывести информацию ее нужно каким - либо образом собрать. Для сбора информации о ссылках создайте файл links.txt и разместите его в выделенной вами директории вашего сайта (я размещаю в корневой).

Несколько замечаний про формат базы данных:

1. База данных может содержать комментарии. Комментарии начинаться с "#" и продолжаются до конца строки.
2. Если поле не содержит данных в нашем формате то она считается комментарием. (Как минимум, для баз с изменяемым числом полей) формат подразумевает определенное или большее количество полей.

Сейчас следует определиться какая информация будет содержаться в базе данных ссылок. (То есть с структурой таблицы базы данных). Итак наша таблица минимально может содержать следующие поля:

1.vis - Видимость записи (для пользователей сайта) 1- выводить 0 -нет
1.name- Название ресурса
2.url- URL ресурса
3.sab- Короткое описание ресурса
4.*email - E-mail веб-мастера ресурса
* - (необязательное поле
Таблица с ссылками физически будет выглядеть следующим образом:

1|Программы для бизнеса|http://www.softm.vov.ru/|Решения для Интранет на основе PHP, 1С - для всех.|softm@ukr.net
1|Бизнес-Монитор|http://www.bismon.lviv.ua/|Каталог бизнес ресурсов. Масса полезной информации для ведения бизнеса.|shk@ukr.net
0|Архив Компьютерной документации|http://anom.al.ru|На сайте представлено большое количество документации по C, C++, CGI/Perl, PHP, HTML|
1|Сайт "Стражника данных" для 1С:|http://warder.netfirms.com|Стражник руководит резервным копированием баз и запуском 1С программ|

Программа реализующая вывод ссылок в виде одной страницы, выглядит довольно просто:

<?

//---

$GLOBALS['links_file']="links.txt";

function KillSpaces($str){

return trim(preg_replace("/[ ]{1,}/"," ",$str));

}

function IsSpace($str)

{

if (strlen(KillSpaces($str))==0) return 1; else return 0;

}

//---

Все это можно вынести в отдельный файл. Однако для простоты я привел все в одном.
(Именно для этого использован массив глобальных переменных)

$a_file=file($GLOBALS['links_file']);end($a_file);$num_elem=count($a_file);

$k=0;

Читаем таблицу ссылок в массив. Получаем количество элементов

for($j=0;$j<$num_elem;$j++)

{

Тут начинается цикл, заполняющий данными массивы. Вывод этих данных состоится в
следующем цикле.Это сделано для того чтобы иметь возможность отсортировать данные

$line=$fcontents[$num_elem-$j-1];

Получаем

$a_file[$i]=preg_replace (

array("/(.*)#.*/s","/[ ]{2,}/m","/[\n\t]{1,}/" ),

array("\\1" ," " ,"" ), $a_file[$j]);

Удаляем из строки комментарий, два и более пробелов подряд заменяем на один пробел, забираем
символ перевода строки

if (IsSpace($a_file[$i])) continue;

Если после обработки строка пустая то пропускаем ее

if (!preg_match("/^([^\|]*)\|([^\|]*)\|([^\|]*)\|([^\|]*)\|([^\|]*)/",$a_file[$i],$a_var))
 continue;

Если строка не совпадает с нашим форматом также пропускаем ее

if($a_var[1]=="0") continue;

Если видимость статьи установлена в 0 то также пропускаем ее, кроме того заносим поля в массив $a_var

$Aname [$k]=$a_var[2];

$Aurl [$k]=$a_var[3];

$Asab [$k]=$a_var[4];

$Aemail[$k]=$a_var[5];

Заполняем массивы полями базы данных (фактически это двухмерный массив но мне больше
понравилось использовать отдельные 4-ре массива.)

prev($fcontents);

$k++;

}

Берем предыдущую запись (то есть читаем строки в файле снизу вверх)

$num_elem=$k-1;

Количество (видимых пользователю) записей
array_multisort($Aurl,$Aemail,$Asab,$Aname);

Сортируем 4-ре массива сразу (по URL)

?>

<table border="1">

<?

for ($i=0;$i<count($Aname);$i++)

{

echo "<tr><td><p>$gray_0<b>$Aname[$i]</b><br>$Asab[$i] ";

if ($Aurl[$i]!="") echo "<a \"_blank\" href=\"$Aurl[$i]\">Перейти>>></a> ";//

if (!IsSpace($Aemail[$i]))echo "<a href=\"mailto:$Aemail[$i]\">e-mail</a> ";

echo "</p></td></tr>";

}

?>

В этом цикле выводятся все ссылки из заполненных таблиц.

Ссылки по теме:

1. Статьи по "регулярным выражениям" на сайте Программы для бизнеса Перейти
2. FAQ по PHP на сайте "Программы для бизнеса" Перейти


Тотоев Александр, www.czar.ru, www.nova-wings.ru

Программирование на PHP. Галерея фотографий (картинок)

Предлагаю вашему вниманию пример программирования на языке php с использованием баз данных mysql (в одном из вариантов программы) на примере создания галереи фотографий, картинок и т.п. Картинки в предпросмотре должны быть определенной ширины (чтобы не расползалась страница). Подобный вариант используется мной здесь (2 вариант) и здесь (1 вариант).

Галерея имеет следующие свойства:

  • предпросмотр;
  • навигация "вперед-назад";
  • навигация по номерам страниц галереи;
  • наличие описаний к картинкам;
  • администрирование описаний к картинкам;
  • варианты 2 и 3 имеют возможность изменять порядок вывода картинок;
  • вариант 3 сделан с использованием базы mysql
  • варианты 1 и 3 легко преобразуемы в галерею с возможностью дополнения галереи посетителями;
  • если вы обнаружили еще какие-то свойства галереи, буду рад выслушать ваше мнение по адресу totoeval@mtu-net.ru

Вариант 1
Программа ищет файлы картинок в указанном ей каталоге с маленькими картинками (предпросмотр). Затем она ищет описания для выводимых картинок в текстовом файле. Определяет кол-во картинок и создает навигацию по галерее. Определяет размеры картинок и выводит их с описаниями и с яваскриптом на каждой картинке, который открывает большой вариант картинки в новом окне с размерами на 40 пикселей больше размера картинки с возможностью скроллинга, если таковой окажется необходим для просмотра картинки полностью (при малом размере экрана).

Вот собственно и код варианта:

<html>
<head>
<TITLE>Photo-galery</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Windows-1251">
<LINK REL=STYLESHEET TYPE="text/css" href="../../style.css">
</head>
<body leftmargin=0 topmargin=0 marginwidth="0" marginheight="0">
<table width=650 cellspacing=0 cellpadding=5 border=0 cols=2><tr><td>
<div align="center">
<br>
<p align="center" class="zag-main">Картинная галерея.</p>
<?
// Пишем переменные, которые зависят от Вас
$scrpic=10; // максимальное кол-во фоток на странице
$big='../pic/big_regats/'; // путь к большим картинкам
$small='../pic/small_regats/'; // путь к малым картинкам
$ini=$DOCUMENT_ROOT.'/avrora/pic/read/read_regats.ini';
// путь к файлу с текстами к картинкам
//В данном случае, файл строится так: строка с названием картинки (без расширения файла)
//затем строка с подписью к картинке
//затем название следующей картинки и так далее.
//Например:
//1
//Моя первая фотография
//rt
//моя фотография rt.jpg
//и так до последней картинки. Если подписи к картинке нет, то надо оставлять пустую строку.
//
$kav="'";
//одинарные кавычки пригодятся нам потом в таком виде
//для отображения в браузере в яваскрипте. Там необходимо иметь оба вида кавычек,
//а для php надо еще поставить выводимое выражение в кавычки.
$podp='увеличить'; //надпись под картинкой,
// побуждающая клиента нажать на картинку для увеличения
$style_zag2='zag2-main'; // стили текста на странице
$style_osn='osn-main'; // стили текста на странице
$style_link='link'; // стили текста на странице
//
//сама программа
$text=file($ini); // читаем файл с подписями к картинкам в массив $text
$dir=$small; // указываем путь к каталогу малых фотографий
$handle=opendir($dir); // читаем заголовок каталога
$si=0; // счетчик файлов в папке
while ($file = readdir($handle)) { // читаем файл, пока не закончатся
if ($file!="..") { // исключаем из списка файлов "." и ".." (корень и верхний каталог).
$pic[$si]=$file; //присваиваем текущему элементу массива с именами файлов имя текущего файла
$si++; //плюсуем к счетчику файлов в папке 1
}
}//следующий файл
$maxpic=count($pic)-1; // сколько файлов в папке с малыми картинками
if ($begin=="") { // если на страницу зашли впервые, то $begin присваеваем 1
$begin=1;
}
$end=$begin+$scrpic-1; // $end - номер последней картинки на странице
if ($end>$maxpic) {
//если последний номер на странице больше кол-во картинок в папке,
//то он равен последнему
$end=$maxpic;
}
$beginrew=$begin-$scrpic; // при переходе назад, начинаем показывать картинки с номера,
//равному "первый номер текущей страницы минус кол-во картинок на странице"
$beginfw=$begin+$scrpic; // при переходе вперед, начинаем показывать картинки с номера,
//равному "первый номер текущей страницы плюс кол-во картинок на странице"
$hrefrew='<a href='.$PHP_SELF.'?begin='.$beginrew.'
class='.$style_zag2.'>назад</a>';
// создаем ссылку "назад"
$hreffw='<a href='.$PHP_SELF.'?begin='.$beginfw.'
class='.$style_zag2.'>вперед</a>';
//создаем ссылку "вперед"
$navig=$hrefrew.' || '.$hreffw; // ставим между ссылками "назад-вперед" символ "||"
if ($beginrew<=0) { // если мы на первой странице, то ссылка назад не нужна
//$hrefrew='<a href='.$PHP_SELF.'?begin='.$beginrew.'
class='.$style_zag2.'>назад</a>';
$navig=$hreffw;
}
if ($beginfw>$maxpic) { // если мы на последней странице, то ссылка вперед не нужна
//$hreffw='<a href='.$PHP_SELF.'?begin='.$beginfw.'
class='.$style_zag2.'>вперед</a>';
$navig=$hrefrew;
}
//вывод на экран номеров страниц галереи
$scrmax=ceil($maxpic/$scrpic); // вычисляем, сколько страниц с картинками
for ($scr=1; $scr<=$scrmax; $scr++) {
// начиная с первого номера до кол-ва страниц галереи
$beginsrc=($scr-1)*$scrpic+1; // вычисляем номер картинки,
// с которого будут выводиться картинки на странице
if ($beginsrc==$begin) { // если страница текущая,
// то ее номер выводим в виде простого текста, а не ссылки
echo ' <span
class='.$style_zag2.'>'.$scr.'</span> ';
}
else { // если страница не текущая, то выводим ссылку на нее и передаем параметры:
// номер картинки, с которой начать выводить на этой странице
echo ' <a href='.$PHP_SELF.'?begin='.$beginsrc.'
class='.$style_zag2.'> '.$scr.' </a> ';
}
}
echo '<p align=center
class='.$style_zag2.'>'.$navig.'</p>';
//вывод на экран навигации "вперед-назад"
for ($i=$begin; $i<=$end; $i++) { // начиная с первой картинки на странице,
// перебираем картинки вплоть до последней на странице
for ($j=0; $j<sizeof($text); $j++) { //читаем файл ини и собираем описания
$name_file=explode(".",$pic[$i]); //выделяем в названии файла его имя (без расширения)
if (trim($text[$j])==$name_file[0]) { //ищем название картинки,
//предварительно обрезав пробелы вокруг названия картинки в файле
//(если текущее название картинки $pic[$i] совпадает с проверяемым $text[$j])
$descript=trim($text[$j+1]);
//если картинка найдена, то в $descript пишем описание к картинке
}
else { // если название картинки не совпадает с искомым, то плюем на него
}
}
$photo=$big.$pic[$i];
//присваиваем $photo имя малого файла+путь к папке с большими картинками
$size=getiize($photo); // читаем информацию о картинке
$width=$size[0]+40; // получаем ширину картинки и + 40 (свободное поле вокруг картинки)
$height=$size[1]+40; // получаем высоту картинки и + 40 (свободное поле вокруг картинки)
$sxp=$size[2]; // получаем тип (расширение файла картинки)
$smphoto=$small.$pic[$i];
//присваиваем $smphoto имя малого файла+путь к папке с малыми картинками
$smsize=getiize($smphoto); // читаем информацию о картинке
$smwidth=$smsize[0]; // получаем ширину картинки
$smheight=$smsize[1]; // получаем высоту картинки
$smexp=$smsize[2]; // получаем тип (расширение файла картинки)
$winstat='toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,
resizable=1,width='.$width.',height='.$height;
//статус открываемого окна с большой картинкой
//выводим таблицу галереи.
//если номер картинки четный, то картинка слева, а описание справа и наоборот
//делаем это для неужасного внешнего вида галереи
//Вы можете разположить картинки как Вам заблагорассудится.
//итак:
?><table width=420 cellspacing=0 cellpadding=5 border=0 cols=2><tr><?
//выводим одинаковую часть кода таблицы дл ячейки картинки
//Далее выводим картинки в ячейках таблиц с описаниями. Делаем все с "предпросмотром"
//"предпросмотр предпочтителен, потому что не надо сразу грузить большие файлы,
//а клиент если захочет, сам загрузит то, что его заинтересовало в новых окнах.
//
if ($i/2==ceil($i/2)) { // если номер картинки на странице четный
echo '<td width=210 rowspan=2>
<p align=right class='.$style_osn.'>'.$descript.'</p>
</td><td hight='.($smheight+2).'>
<table width=202 cellspacing=1 cellpadding=0 border=0 bgcolor="#000000"
border=0><tr><td>
<a href='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.',
'.$kav.$i.$kav.', '.$kav.$winstat.$kav.');">
<img src='.$smphoto.' width='.$smwidth.' height='.$smheight.'
border=0 alt="увеличить">
</a>
</td></tr></table>
</td></tr>
<tr><td valign=top>
<center>
<a href='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.',
'.$kav.$i.$kav.', '.$kav.$winstat.$kav.');"
CLASS='.$style_link.'>'.$podp.'
</a>
</center>
</td></tr></table>';
}
else { // если номер картинки нечетный
echo '<td align=left><table width=202 cellspacing=1 cellpadding=0 border=0
bgcolor="#000000"><tr>
<td hight='.($smheight+2).'>
<a href='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.',
'.$kav.$i.$kav.', '.$kav.$winstat.$kav.');">
<IMG SRC='.$smphoto.' width='.$smwidth.' height='.$smheight.'
border=0 alt="увеличить">
</a>
</td></tr></table>
</td>
<td width=210 rowspan=2>
<p align=left class='.$style_osn.'>'.$descript.'</p>
</td></tr>
<tr><td valign=top>
<center>
<a href='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.','.$kav.$i.$kav.',
'.$kav.$winstat.$kav.');" CLASS='.$style_link.'>'.$podp.'
</a>
</center>
</td></tr></table>';
}
}
//вывод на экран "вперед-назад"
echo '<p align=center
class='.$style_zag2.'>'.$navig.'</p>';
//вывод на экран номеров страниц
echo '<div align=center>';
for ($scr=1; $scr<=$scrmax; $scr++) {
$beginsrc=($scr-1)*$scrpic+1;
if ($beginsrc==$begin) {
echo ' <span
class='.$style_zag2.'>'.$scr.'</span> ';
}
else {
echo ' <a href='.$PHP_SELF.'?begin='.$beginsrc.'
class='.$style_zag2.'> '.$scr.' </a> ';
}
}
?>
</div>
</td></tr></table>
</body>
</html>

Программа администрирования текстов описаний:
Была применена в моей статье Импортирование информации с чужого сайта на свой сайт в свой дизайн. Я считаю этот способ самым проостым для начинающего программиста. Более сложный способ обновления я собираюсь сделать в будущих статьях.
Конечно, можно делать более серьезные интерфейсы, но в этом варианте, который конечно не рассчитан на ламера, можно быстро править сразу все позиции.
Вот собственно код:

<html>
<head>
<title>admin weather</title>
</head>
<body>
<?php
$adr=$DOCUMENT_ROOT."/avrora/pic/read/read_regats.ini";
//адрес файла,в котором и будут записываться названия файлов с описаниями
$password='pass'; // простенькая система авторизации
$eror='Password eror!';
$old=file($adr); //читаем то, что сейчас есть в файле
if ($submit) { // проверяем на нажатость кнопки
if ($pass==$password) {
$fp=fopen($adr,"w");
fwrite ($fp, $ini); //записываем в файл измененные данные
fclose($fp);
$old=file($adr);
}
else {
echo $eror;
}
}
?>
<form method=post action="<?php echo $PHP_SELF?>">
//информация, введенная в форму, обрабатывается этим же файлом
password:<input type=text name=pass><br>
inicialisation:<textarea name="ini" rows=15 cols=60>
<?
for ($i=0; $i<sizeof($old); $i++) {
echo $old[$i], ""; // выводим на экран текущий вариант файла
}
?>
</textarea>
<br>
<input type=submit name="submit" value="Enter">
</form>
</body>
</html>

В этом варианте, файл создаем так, как написано в комментарии к программе:
1
Моя первая фотография
rt
моя фотография rt.jpg

где 1 и rt - имена файлов, а строки под ними соответственно описания к ним.

Вариант 2
Отличие этого варианта отпредыдущего в том, что программа читает файл инициализации галереи. В каждой строке такая конструкция (так надо заполнять файл для этого варианта!):
1.jpg|Моя первая фотография
rt.jpg|моя фотография rt.jpg
где символ "|" - это разделитель между описанием и именем файла картинки.

Как видно, в этом варианте надо писать в файле имя файла картинки с расширением. Если это вам это очень мешает, то можете переделать так, чтобы было в файле только имя, а расширение определялось бы автоматически, основываясь на первом примере.
Алгоритм такого варианта будет:
определить имя картинки, считать имена файлов в папке с файлами, обрезая у имен файлов расширения, находим нужный, сравнивая каждый раз с тем, что взяли из файла. Именно совпавший и будет искомым.

Далее программа, создав массив из имен и описаний картинок, определяет, на какой странице галереи клиент находится и выводит ему соответственно ту или иную страницу.
Сам движок галереи остается тем же, как вы наверное заметили.
Изменяются некоторые его части.
Вот сам код:

<html>
<head>
<TITLE>Photo-galery</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Windows-1251">
<LINK REL=STYLESHEET TYPE="text/css" href="../../style.css">
</head>
<body leftmargin=0 topmargin=0 marginwidth="0" marginheight="0">
<table width=650 cellspacing=0 cellpadding=5 border=0 cols=2><tr><td>
<div align="center">
<br>
<p align="center" class="zag-main">Картинная галерея.</p>
<?
//Пишем переменные, которые зависят от Вас
$scrpic=10; // максимальное кол-во фоток на странице
$big='../pic/big_regats/'; // путь к большим картинкам
$small='../pic/small_regats/'; // путь к малым картинкам
$ini=$DOCUMENT_ROOT.'/avrora/pic/read/read_regats1.ini';
// путь к файлу с текстами к картинкам
//В данном случае, файл строится так: строка с названием картинки (без расширения файла)
//затем строка с подписью к картинке
//затем название следующей картинки и так далее.
//Например:
//1|Моя первая фотография
//rt|моя фотография rt.jpg
//и так до последней картинки. Если подписи к картинке нет, то надо оставлять пустую строку.
//
$kav="'"; // одинарные кавычки пригодятся нам потом в таком виде
// для отображения в браузере в яваскрипте. Там необходимо иметь оба вида кавычек,
// а для php надо еще поставить выводимое выражение в кавычки.
$podp='увеличить'; // надпись под картинкой,
//побуждающая клиента нажать на картинку для увеличения
$style_zag2='zag2-main'; // стили текста на странице
$style_osn='osn-main'; // стили текста на странице
$style_link='link'; // стили текста на странице
//сама программа
$text=file($ini); // читаем файл с подписями к картинкам в массив $text
for ($i=0; $si<sizeof($text); $i++) {
// читаем файл ини и сохраняем имена картинок.
$si=$i+1;
$string=explode("|",$text[$i]);
$pic[$si]=$string[0]; // присваиваем текущему элементу массива с именами файлов имя текущего файла
$description[$si]=$string[1];
}
$maxpic=count($pic); // сколько файлов в папке с малыми картинками
if ($begin=="") { // если на страницу зашли впервые, то $begin присваеваем 1
$begin=1;
}$end=$begin+$scrpic-1; // $end - номер последней картинки на странице
if ($end>$maxpic) {
// если последний номер на странице больше кол-во картинок в папке,
//то он равен последнему
$end=$maxpic;
}
$beginrew=$begin-$scrpic; // при переходе назад, начинаем показывать картинки с номера,
//равному "первый номер текущей страницы минус кол-во картинок на странице"
$beginfw=$begin+$scrpic; // при переходе вперед, начинаем показывать картинки с номера,
//равному "первый номер текущей страницы плюс кол-во картинок на странице"
$hrefrew='<a href='.$PHP_SELF.'?begin='.$beginrew.'
class='.$style_zag2.'>назад</a>';
// создаем ссылку "назад"
$hreffw='<a href='.$PHP_SELF.'?begin='.$beginfw.'
class='.$style_zag2.'>вперед</a>';
// создаем ссылку "вперед"
$navig=$hrefrew.' || '.$hreffw; // ставим между ссылками "назад-вперед" символ "||"
if ($beginrew<=0) { // если мы на первой странице, то ссылка назад не нужна
//$hrefrew='<a href='.$PHP_SELF.'?begin='.$beginrew.'
class='.$style_zag2.'>назад</a>';
$navig=$hreffw;
}
if ($beginfw>$maxpic) {
//если мы на последней странице, то ссылка вперед не нужна
//$hreffw='<a href='.$PHP_SELF.'?begin='.$beginfw.'
class='.$style_zag2.'>вперед</a>';
$navig=$hrefrew;
}
//вывод на экран номеров страниц галереи
$scrmax=ceil($maxpic/$scrpic); //вычисляем, сколько страниц с картинками
for ($scr=1; $scr<=$scrmax; $scr++) {
//начиная с первого номера до кол-ва страниц галереи
$beginsrc=($scr-1)*$scrpic+1; // вычисляем номер картинки,
//с которого будут выводиться картинки на странице
if ($beginsrc==$begin) { // если страница текущая,
//то ее номер выводим в виде простого текста, а не ссылки
echo ' <span
class='.$style_zag2.'>'.$scr.'</span> ';
}
else { // если страница не текущая, то выводим ссылку на нее и передаем параметры:
//номер картинки, с которой начать выводить на этой странице
echo ' <a href='.$PHP_SELF.'?begin='.$beginsrc.'
class='.$style_zag2.'> '.$scr.' </a> ';
}
}
echo '<p align=center
class='.$style_zag2.'>'.$navig.'</p>';
//вывод на экран навигации "вперед-назад"
for ($i=$begin; $i<=$end; $i++) { //начиная с первой картинки на странице,
//перебираем картинки вплоть до последней на странице
$descript=$description[$i];
$photo=$big.$pic[$i];
//присваиваем $photo имя малого файла+путь к папке с большими картинками
$size=getiize($photo); // читаем информацию о картинке
$width=$size[0]+40; // получаем ширину картинки и + 40 (свободное поле вокруг картинки)
$height=$size[1]+40; // получаем высоту картинки и + 40 (свободное поле вокруг картинки)
$sxp=$size[2]; // получаем тип (расширение файла картинки)
$smphoto=$small.$pic[$i];
//присваиваем $smphoto имя малого файла+путь к папке с малыми картинками
$smsize=getiize($smphoto); // читаем информацию о картинке
$smwidth=$smsize[0]; // получаем ширину картинки
$smheight=$smsize[1]; // получаем высоту картинки
$smexp=$smsize[2]; // получаем тип (расширение файла картинки)
$winstat='toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,
resizable=1,width='.$width.',height='.$height;
//статус открываемого окна с большой картинкой
//выводим таблицу галереи.
//если номер картинки четный, то картинка слева, а описание справа и наоборот
//делаем это для неужасного внешнего вида галереи
//Вы можете расположить картинки как Вам заблагорассудится.
//итак:
?><table width=420 cellspacing=0 cellpadding=5 border=0 cols=2><tr><?
//выводим одинаковую часть кода таблицы дл ячейки картинки
//Далее выводим картинки в ячейках таблиц с описаниями. Делаем все с "предпросмотром"
//"предпросмотр предпочтителен, потому что не надо сразу грузить большие файлы,
//а клиент если захочет, сам загрузит то, что его заинтересовало в новых окнах.
if ($i/2==ceil($i/2)) { // если номер картинки на странице четный
echo '<td width=210 rowspan=2><p align=right
CLASS='.$style_osn.'>'.$descript.'</p
></td><td hight='.($smheight+2).'>
<table width=202 cellspacing=1 cellpadding=0 border=0 bgcolor="#000000"
border=0><tr><td>
<A HREF='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.', '.$kav.$i.$kav.',
'.$kav.$winstat.$kav.');">
<IMG SRC='.$smphoto.' WIDTH='.$smwidth.' HEIGHT='.$smheight.'
BORDER=0 alt="увеличить"></A></td></tr></table
></td></tr><tr><td valign=top><center>
<A HREF='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.', '.$kav.$i.$kav.',
'.$kav.$winstat.$kav.');"

CLASS='.$style_link.'>
'.$podp.'</a></center></td></tr></table>';
}
else { // если номер картинки нечетный
echo '<td align=left><table width=202 cellspacing=1 cellpadding=0
border=0 bgcolor="#000000">
<tr><td hight='.($smheight+2).'>
<A HREF='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.', '.$kav.$i.$kav.',
'.$kav.$winstat.$kav.');">
<IMG SRC='.$smphoto.' WIDTH='.$smwidth.' HEIGHT='.$smheight.'
BORDER=0 alt="увеличить">
</A></td></tr></table>
</td><td width=210 rowspan=2><p align=left
CLASS='.$style_osn.'>'.$descript.'</p
></td></tr><tr><td valign=top><center>
<A HREF='.$photo.' "'.$i.'"
onclick="window.open('.$kav.$photo.$kav.', '.$kav.$i.$kav.',
'.$kav.$winstat.$kav.');"

CLASS='.$style_link.'>'.$podp.'</a>
</center></td></tr></table>';
}
}
//вывод на экран "вперед-назад"
echo '<p align=center
class='.$style_zag2.'>'.$navig.'</p>';
//вывод на экран номеров страниц
echo '<div align=center>';
for ($scr=1; $scr<=$scrmax; $scr++) {
$beginsrc=($scr-1)*$scrpic+1;
if ($beginsrc==$begin) {
echo ' <span
class='.$style_zag2.'>'.$scr.'</span> ';
}
else {
echo '<a href='.$PHP_SELF.'?begin='.$beginsrc.'
class='.$style_zag2.'> '.$scr.' </a> ';
}
}
?>
</div>
</td></tr></table>
</body>
</html>

Программа администрирования та же, что и в варианте 1.

Вариант 3
В этом варианте используется база данных mysql вместо текстового файла для хранения описаний, имен картинок и порядка их следования.
Здесь тоже в базе хранятся именя файлов с расширениями (при варианте без расширений, будет тратиться время на пиоск картинки по описанному выше алгоритму, а при заливке картинок через вэбинтерфейс проще хранить имена файлов с расширениями).
Алгоритм работы программы такой же, что и в предыдущем примере. Однако, вместо считывания файла, считывается база галереи. Для ускорения можно было бы поместить операцию считывания в цикл вывода картинок на экран и не считывать все строки базы.
Для создания таблицы базы картинок используйте этот скрипт:

<?
//инициализация mysql:
$mysql_login='my_login';
$mysql_host='host_db';
$mysql_pass='my_password';
$mysql_db='name_db';
//
mysql_connect($mysql_host,$mysql_login,$mysql_pass);
mysql_select_db($mysql_db);
mysql_query("set CHARACTER SET cp1251_koi8") or die ("!--не могу записать");
// эта строка
используется, если сайт в кодировке win, а база в кодировке кои-8.
Если кодировки совпадают, строку надо закомментировать.
$query="CREATE TABLE galery_regats (numer tinyint(4) NOT NULL, name text
NOT NULL, description text NOT NULL)";
$res=mysql_query($query) or die ("!--не могу создать таблицу");
header("location: admin.php"); // переход на страницу администрирования
?>

Программа администрирования:

<html>
<head>
<title>Admin galery</title>
<link rel=stylesheet type="text/css" href="../../style.css">
</head>
<body bgcolor=#eeeeee>
<br>
<?
//логин/пароль
$log='total';
$pas='total';
//инициализация mysql:
$mysql_login='my_login';
$mysql_host='host_db';
$mysql_pass='my_password';
$mysql_db='name_db';
$style_zag2='zag2-main'; // стили текста на странице
$style_osn='osn-main'; // стили текста на странице
$style_link='link'; // стили текста на странице
$kon_str="\n"; // конец строки
$razdel="|"; // разделитель между именем картинки и описанием
?>
<p align="center" class="<? echo $style_zag2; ?>">Картинная галерея.</p>
<?
mysql_connect($mysql_host,$mysql_login,$mysql_pass);
mysql_select_db($mysql_db);
mysql_query("set CHARACTER SET cp1251_koi8") or die ("!--не могу записать");
switch ($prov) { // проверяем состояние переменной $prov
case "edit":
//если пишем новый вариант базы:
if ($login!=$log || $pass!=$pas) { echo "Введите правильно логин/пароль";
} //если пароль неверен
else {
// удаляем текущую базу картинок и создаем пустую таблицу
$query="DROP TABLE galery_regats"
$res=mysql_query($query) or die ("!--не могу удалить таблицу");
$query="CREATE TABLE galery_regats (numer tinyint(4) NOT NULL, name text
NOT NULL, description text NOT NULL)";
$res=mysql_query($query) or die ("!--не могу создать таблицу");
$pics=explode($kon_str,$block); // бьем наш список по символу переноса строки
for ($i=0; $i<sizeof($pics); $i++) { // пишем в базу данные
$string=explode($razdel,$pics[$i]); // бьем строки по символу разделителя
$query="insert into galery_regats (number, name, description) values ('$i',
'$string[0]', '$string[1]')";
mysql_query($query) or die ("!--не могу записать"); // пишем в таблицу
}
}
break;
default:
//если мы зашли не по нажатию на ентер:
//читаем базу картинок и сохраняем в массивы
$zapros="select * from galery_regats order by
numer";$res=mysql_query($zapros);
$kol=mysql_num_rows($res);
if ($kol==0) {
echo "<span class=$style_osn>Нет картинок в галерее.</span>";
}
for ($i=0; $i<$kol; $i++) { // читаем базу и сохраняем имена картинок.
$pic[$i]=mysql_result($res,$i,"name"); // присваиваем текущему элементу массива
$description[$i]=mysql_result($res,$i,"description");
}
break;
}
}
?>
<form method=post action="<? echo $PHP_SELF; ?>">
<textarea name="block" rows="40" cols="40">
<?
//выводим текущее состояние базы картинок
for ($i=0; $i<sizeof($pic); $i++) {
echo $pic[$i].$razdel.$description[$i].$kon_str;
}
?>
</textarea>
<input type="text" name="login" size="10">
<input type="text" name="pass" size="10">
<input type="hidden" name="prov"
value="edit"><input type="submit" name="enter" value="Enter">
</form>
</body>
</html>

Форма заполняется как и во втором варианте.А для получения 3-го варианта в коде программы 2-го варианта строки от строки //сама программа до строки $maxpic=count($pic);//сколько файлов в папке с малыми картинками которые являются блоком считывания файла в массивы, заменяются на блок:

mysql_connect($mysql_host,$mysql_login,$mysql_pass); // соединение с базой(коннект)
mysql_select_db($mysql_db); // выбор базы
mysql_query("set CHARACTER SET cp1251_koi8") or die ("--------не могу записать");
//Если кодировки базы и сайта совпадают - закомментировать эту строку
$zapros="select * from galery_regats order by numer";
$res=mysql_query($zapros);
$kol=mysql_num_rows($res);
if ($kol==0) {
echo "Нет картинок в галерее.";
}
for ($i=0; $i<$kol; $i++) { // читаем файл ини и сохраняем имена картинок.
$si=$i+1;
$pic[$si]=mysql_result($res,$i,"name");
//присваиваем текущему элементу массива с именами файлов имя текущего файла
$description[$si]=mysql_result($res,$i,"description");
}

Результат работы блока точно такой же, что и во втором варианте - массивы $pic и $description, где храним имена файлов картинок и описания к ним. Но работает такая галерея быстрее. Однако, каждый раз, когда хотите залить новую картинку, надо администрить галерею, даже если не нужно описание. А в первом варианте стоит только лишь закинуть в папки файлы картинок.

Таким образом, получаем 3 рабочих варианта программы галереи. Если будут возникать вопросы по работе программы, адаптации под "свой сайт" или по принципам, пишите мне по адресу totoeval@mtu-net.ru


Андрей Кухарчик, июнь 2001, virtualbrest@tut.by

Голосование на РНР!

Речь пойдет о практической работе, которую мы с Вами вместе проведем и усвоим. Голосование - это средство узнать мнение Ваших посетителей по разным вопросам. Сами вопросы могут быть как полезными так и бесполезными - эту тему мы рассматривать не будем. А для нашего примера возьмем простой вопрос - Ваше мнение о сайте?. Предположим, у Вас например появилось желание узнать, что думает большинство посетителей Вашего сайта. Варианты ответов предоставим следующие:

Круто!

Нормально.

Мне все равно.

Это что-то страшное.

Продолжить список Вы можете уже сами... Для работы нам понадобится некоторое знание основ HTML, РНР версии 3 или выше и три файла. Три - потому что в первом будем спрашивать посетителя о его мнении, во втором хранить результаты, и в третьем - выводить их и обрабатывать. Собственно говоря, нет надобности разносить все эти функции в разные файлы, но для простоты и удобства мы сделаем так. Первый файл будет иметь имя index.phtml, второй - golos.txt и третий - golos.phtm
l.Создать их для Вас не составит особого труда, и это то, с чего мы и начнем. Когда Вы все сделаете и зальете готовые файлы к себе на сервер, не забудьте установить атрибуты файла golos.txt таким образом, что бы он был доступен для записи. Обычно, это атрибуты 666 или 777. Сделать это можно как правило с помощью Вашего FTP менеджера. Если нет, воспользуйтесь IE 5.0 и выше в режиме FTP, тогда нужно просто посмотреть свойства уже залитого на сервер файла и установить все галочки.

Index.phtml

Вы можете обозвать этот и другие наши файлы так, как Вам угодно, только не меняйте расширений (кроме, конечно, txt). Это необходимо для работы РНР, на котором и будет реализован алгоритм голосования. Дизайн и оформление предлагаю Вам сделать самостоятельно, я не буду в статье обращать на это внимание.

Прежде всего сделаем нужную форму. Можно было бы воспользоваться любым редактором HTML, они неплохо делают сами формы, но я привожу уже готовый и работоспособный код.

<FORM METHOD="POST" action="golos.phtml">
<TABLE BORDER=1><TR><TD><TABLE BORDER=0>
<TR><TD>Ваше мнение о сайте?</TD></TR>
<TR><TD><INPUT TYPE=radio NAME=answer VALUE=1>Круто!</TD></TR>
<TR><TD><INPUT TYPE=radio NAME=answer VALUE=2>Нормально</TD></TR>
<TR><TD><INPUT TYPE=radio NAME=answer VALUE=3>Мне все равно</TD></TR>
<TR><TD><INPUT TYPE=radio NAME=answer VALUE=4>Это что-то страшное!</TD></TR>

<TR><TD><INPUT TYPE=Submit NAME=vote VALUE=" отправить "></TD></TR>
<TR><TD><INPUT TYPE=Submit NAME=result VALUE="смотреть результат ">
</TD></TR></TABLE></TD></TR></TABLE></FORM>

Пока это все. Тут нет и строчки кода РНР, но на будущее полезно иметь возможность вставить сюда что-то, так что расширение файла выбрано правильно, тем более что оно больше ни на что не влияет. В коде все просто, и сделать подобное или похожее легко в любом редакторе. Мы просто предлагаем указать с помощью переключателя нужный вариант ответа и нажать на кнопку Отправить.Этот код можно легко интегрировать в любые странички и править так, как только вздумается. Только нужно обращать внимание на соответствие имен и значений переменной в форме. И что самое главное - данные формы должны передаваться в скрипт РНР с обработкой результатов, поэтому имя файла в action должно соответствовать имени файла с скриптом. Напомню, все имена форм, присвоенные в этом файле, станут соответствующими переменными в скрипте РНР, куда отправляются данные формы. Так как тут ничего сложного больше не предвидится, пойдем дальше.

Golos.txt

Здесь надо определиться, в каком формате мы будем хранить вводимую информацию. Проще всего организовать четыре строки (по количеству вариантов ответов) и считать их номера соответствующими номеру выбранного варианта ответа. Все это безобразие можно считывать с помощью команды РНР ввода файла в массив, при этом не забывайте, что массив всегда начинается с индекса ноль. Соответственно - первая строка нашего файла не будет использована, и ввести туда можно все что угодно. Например - информацию о файле:Результаты голосования. Если это сделано, введите еще четыре строки с нулями. Не забывайте нажимать ввод для перевода строки. Это - готовые результаты (пока только начальные) нашего голосования. Так как пока никто не проголосовал :-) они нулевые.

Golos.phtml

Вот и дошли мы до самого главного и интересного. С самого начала я приведу весь код скрипта, а дальше дам пояснения в его применении и работе.

<?php
$file = "golos.txt";
$a = file($file);
$i = 1; $fi = Count($a);
$n = 0;
while ($i <= $fi):
$a[$i] = trim(str_replace ("\n","", $a[$i]));
$n = $n+$a[$i];
$i++;
endwhile;

if ($answer != "") {
echo "<br>Спасибо, Ваше мнение учтено:";
$a[$answer]++; $n++;

$rez = "Результаты голосования!\n".$a[1].
"\n".$a[2]."\n".$a[3]."\n".$a[4];
$fp = @fopen($file,"w");
if ($fp) { $counter=fputs($fp,$rez); fclose($fp); }
else { echo "Произошла ошибка записи результатов!"; }

} else { echo "<br>Результаты голосования";
}
echo "<br>Круто! - <b>".$a[1]."</b>";
echo "<br>Так себе - <b>".$a[2]."</b>";
echo "<br>Сойдет - <b>".$a[3]."</b>";
echo "<br>Это что-то страшное! - <b>".$a[4]."</b>";
echo "<br><br>Всего проголосовало:".$n;
?>

Опять же хочу предупредить, что код не самый лучший и простой, но зато логичный и работоспособный. Вариантов реализации масса, но мне не хотелось брать что-то уже готовое, и поэтому я, не особо заботясь об удобочитаемости и дизайне (это Вы и сами можете сделать :-), написал свой собственный код, что заняло вместе с настройкой и отладкой буквально полчаса. Скрипт ориентирован на конкретно поставленную задачу, но Вам ничего не стоит переделать его под свое количество ответов на вопрос. Напомню - наша главная задача на практическом примере научиться создавать свои собственные системы опроса и голосования. Теперь о том, как все работает.

В первых строчках мы определяемся с именем файла результатов и считываем результаты голосования в массив данных с именем $a. Дальше идет цикл, в котором мы обрабатываем полученный массив таким образом, что бы он не содержал символов перевода каретки (ввод строки) и пробелов: $a[$i] = trim(str_replace("\n","", $a[$i])); Параллельно ведем подсчет количества проголосовавших, что не сложно так как это просто сумма значений нашего массива. Удалять символы ввода и пробела необходимо для преобразования считанных данных из символьной строки в целое число. Это можно сделать разными методами, но в этом случае просто удаляются символы "\n" (что в РНР соответствует переводу строки) и обрезаются пробелы с начала и с конца строки функцией trim ().Результаты заносятся обратно в массив, но уже в виде целочисленного значения, которое можно сложить, увеличить, делить и т.д. Нас будет интересовать увеличение на единицу определенного элемента массива, номер которого (его индекс) хранится в переменной $answer, которая в свою очередь, пришла к нам по наследству из формы.

После обработки полученного массива скрипт должен принять решение относительно выбранного посетителем режима - или просто показать результаты, или добавить голос в соответствующую позицию. Достигается это проверкой переменной $answer, в которой сохраняется значение выбранного посетителем сайта варианта голосования. Если эта переменная пуста, значит была нажата кнопка показа результатов, и скрипт пропустит блок подсчета голоса. Если переменная $answer не пуста, в ней содержится номер выбранного варианта голосования, а значит, мы можем просто увеличить на единицу значение нужной ячейки массива: $a[$answer]++; Кроме того нужно увеличить значение количества проголосовавших для того, что бы учесть голос только что проголосовавшего человека.

Когда нужная ячейка массива увеличена, пришла пора записать результаты в файл. Для этого сначала открывается соединение с файлом: $fp = fopen($file,"w"); Символ w указывает на необходимость очистки содержимого файла перед записью. Если соединение не установлено, выводится сообщение об ошибке, если установлено - предварительно отформатированное значение переменной $rez записывается в файл. Переменная $rez формируется следующим образом: значение всех ячеек массива (кроме самой первой - нулевой, которая не используется) склеивается таким образом, что бы разделителем был символ перевода строки. Это позволит в дальнейшем корректно считать полученный таки образом файл. Для склейки строк в РНР применяется разделитель - точка. Обратите внимание, что наш массив из целочисленного перешел в разряд символьных, и может использоваться и обрабатываться любым доступным РНР способом.

И наконец - пришла пора вывести результаты на экран. Не нужно забывать о переводе строки в HTML, что несколько иное, чем в РНР. Делается это простым выводом на экран (а значит и в код HTML) тега <BR>.Когда отформатированные результаты выведены, скрипт заканчивает свою работу. Этот блок можно организовать тоже по-разному, а примененный тут метод самый простой. Лучше всего вложить результаты и пункты в табличку, тогда выведенная информация будет смотреться более красиво. Если Вы обратили внимание, эта часть скрипта выполняется в любом случае, как и считывание данных из файла. Таким образом достигается гарантированный вывод результатов на экран.

Вот и вся работа. Надеюсь, что Вы теперь без труда сможете организовывать опросы своих посетителей на различные темы. Кроме того, голосование можно оснастить другими полезными функциями – например, подсчетом процентного соотношения голосов, графическим представлением результатов, памятью на IP опрошенного, чтобы дважды не голосовали. Да мало ли… Только тут придется Вам проявить собственную фантазию и знание элементарной алгебры (вот где оно аукнулось :-). А узнать более подробно о функциях и операторах РНР Вы всегда сможете в Интернете. Например тут: http://virtual.bresttelecom.by/php. Если Вы хотите посмотреть в Интернете на рабочий пример голосования - воспользуйтесь адресом http://virtual.bresttelecom.by- на похожем алгоритме там реализован опрос мнения посетителей. Кроме того, там Вы так же найдете пример голосования с графическим выводом результатов. Если возникнут затруднения или вопросы, с большим удовольствием отвечу Вам по электронной почте.


Дмитрий Лебедев, Клуб PHP-разработчиков

Безопасный и удобный поиск на PHP

Главное, с чем сталкиваешься при написании скрипта для поиска - то, что все кажется простым, но объем кода быстро нарастает.

Обработка строки

Первым делом надо порезать ручками строку.

$search = substr($search, 0, 64);

64 символов пользователю будет достаточно для поиска. Теперь каленым железом выжжем все "ненормальные" символы.

$search = preg_replace("/[^(w)|(x7F-xFF)|(s)]/", " ", $search);

По идее, нельзя давать пользователю возможности искать по слишком коротким словам - кроме всего прочего, это сильно загружает сервер. Итак, разрешим искать только по словам, которые длиннее двух букв (если ограничение больше, надо заменить "{1,2}" на "{1, кол-во символов}").

$good = trim(preg_replace("/s([^s]{1,2})s/", " ", ereg_replace("[ ]+", " "," $search ")));

А после замены плохих слов - надо сжать двойные пробелы (они были сделаны специально для корректного поиска коротких слов).

$good = ereg_eplace("[ ]+", " ", $good);

Логика

Допустим, мы хотим предоставить пользователю возможность выбирать логику поиска - искать все слова или только одно из нескольких. Если вы хотите сделать как в Яндексе - два амперсанта означают "И" (слово1&&слово2&&слово3) или как-то еще, то я не советчик. Шаманство со строками на небольшом сайте imho не оправдывает затраченного времени. Поэтому форму для поиска рисуем так:

<form name="some">
<input type=text name="stroka">
<select name="logic">
<option value="OR">искать любое из слов</option>
<option value="AND">искать все слова</option>
</select>
</form>
А в поисковом скрипте лишний раз проверяем, что пользователь ввел:

if ($logic!="AND" && $logic!="OR")

$logic = "OR";

Как будет использоваться логика — ниже.

Релевантность

Наверное, в том же Яндексе все видели ссылочку "сортировать по релевантности". Это оно и есть. Сортировка результатов по количеству совпадений слов.

Отчасти, кстати, такая сортировка снимает проблему обработки логики поиска. Но с БД MySQL делать такую сортировку очень сложно. Надо сперва выбрать, где есть все слова, потом записи, где разные слова (исключив предыдущие). Если у вас постраничный вывод - то вообще дело труба!

Статистика поиска

Неплохо будет сразу информировать пользователя, сколько он нашел строк таблицы. Для этого делается дополнительный запрос в базу:

$query = "SELECT id FROM table WHERE field LIKE '%". str_replace(" ", "%' OR field LIKE '%", $good). "%'";

Для статистики по отдельным словам можно сделать следующее:

$word = explode(" ", $search);
while (list($k, $v) = each($word)) {
if (strlen($v)>2)
$stat[]="$v:". mysql_num_rows(mysql_query("SELECT id FROM table WHERE field LIKE '%$v%'"));
else
$stat[]="$v: <font color=#cc0000>короткое</font>";
};
$word_stats = "Статистика слов: ". implode("", $stat). "<br>";
unset($stat);

Постраничный вывод результатов

Ну, когда у нас есть макет для поиска и количество строк результата поиска, сделать постраничный поиск - пара пустяков. Проверяем переменную $page (не меньше 0, не больше $results_amount/$rows_in_page).

В запрос, который подсчитывает количество строк (смотри выше), пишем нужные нам поля и поля для сортировки. А потом дописываем

if ($page==0)
$request .= "LIMIT $rows_in_page";
else
$request .= "LIMIT ". $page*$rows_in_page. ",". $rows_in_page;

(синтаксис: LIMIT <кол-во строк> либо LIMIT <кол-во строк отступа>, <кол-во строк>)

В результате выполнения подобного запроса мы получим именно те самые строки, которые надо выводить на странице.

Для навигации можно либо рисовать ссылки на следующую и предыдущую страницы, либо, что сложнее, делать панель навигации на несколько страниц.

if ($page>0)
print ("<a href=search.php?search=". rawurlencode($good). "&page=". ($page-1). ">предыдущая страница</a>");

if ($page<$results_amount/$rows_in_page)
print ("<a href=search.php?search=".rawurlencode($good). "&page=". ($page+1). ">следующая страница</a>");

Подсветка

Чтобы подсвечивать светом или жирным шрифтом искомые слова в тексте, надо сделать всего лишь следующее:

$highlight = "(". str_replace(" ", "|", $good). ")";

Пробелы (а они у нас между словами стоят поодиночке, и нигде двойной пробел не встречается, к тому же с концов строки мы их тоже вырезали) достаточно заменить на вертикальную черту - разделитель вариантов в регулярных выражениях. "Плохие" слова мы не подсвечиваем, потому что в базе их не ищем :).

В коде, который выводит текст пишем:

$row["text"] = ereg_replace($highlight, "<font color=#cc0000>1</font>", $row["text"]);

После написания выпуска я кинулся, было, писать и себе "подсветку". Не тут-то было! У меня в тексте встречаются теги HTML, поэтому пришлось много подумать... Получилась вот такая вещь (строка со словами для подсветки есть):

$text = eregi_replace(">([^<]*)$words", ">1<font color=#cc0000>2</font>3<", $text);

Приходится смотреть, нет в теге ли это слово. Однако тут встает проблема ресурсоемкости такой замены (мой K6-266 над текстом в 5 килобайт думал целых семь секунд). Печально.

Итог

Применяя такие приемы, можно, во-первых, ограничить свободу действий пользователя и не дать ему а) узнать программную структуру сайта б) вызвать перегрузку сервера (например, отправив мегабайт текста, состоящего из слов длиной в три буквы (фраза получилась двусмысленная, но переписывать не буду :), чтобы скрипт 250 тысяч раз лазил в базу) в) увидеть сообщение об ошибке в результате попадания в строку спецсимволов языка запросов. Во-вторых, некоторое удобство для пользователя - постраничный вывод и подсветка.


GUGO

Что такое PHP-Nuke или Web-портал за 15 минут

Когда человек попадает в интернет, его все удивляет. В определенный момент у пользователя возникает острое желание создать свой собственный сайт. Тут ему приходят на помощь сайты, где пользователь может бесплатно зарегистрироваться и получить, кроме почты, немного дискового пространства для «домашней странички». Там он может разместить любую информацию, однако жить или умереть сайту, решает владелец сервера.

Эта статья предназначена для тех пользователей, кто не знаком с программированием на PHP и не может собственными силами создать такой портал, как, например, GameBox.ru. Но желание настолько сильное, что человек готов выполнить ряд действий для приближения своей мечты к реальности. Итак, мы подошли вплотную к тому факту, что вы готовы к установке PHP-Nuke.

Нюка – это бесплатная портальная система, которая позволяет поддерживать сайт с различными сервисами без особых временных затрат на программирование. Распространение PHP-Nuke происходит свободно по лицензии GNU GPL Licence version 2.0. Спасибо автору PHP-Nuke.

Что надо для установки

Начнем с того, что вы не разбираетесь в HTML. В этом случае вы сможете установить нюку, но поддерживать и изменять внутреннюю структуру сайта вам будет проблематично.

Последняя версия PHP-Nuke на сегодняшний день - это 5.4. Она позволяет создать сайт, в котором будет:

  • Рубрикатор (топики, по которым ведется наполнение сайта)
  • Новостная лента (с комментариями)
  • Журнальный архив
  • Избранное (отдельный журнал)
  • Рейтинг статей (по голосам, просмотрам)
  • Рассылка материалов сайта
  • Встроенный Форум (отличное нововведение версии 5.4)
  • Голосование по различным вопросам
  • Файловый архив (с рубрикатором и статистикой обращений)
  • Внутренняя статистика (по логам)
  • Возможность модульного наращивания
  • *Возможность модульного наращивания

А также удобная система администрирования сайта, которая позволяет выделять доступ различным его пользователям (далее - админы).

Модульное наращивание позволяет инсталлировать на ваш сайт разного рода add-on’ы, которые пишут другие пользователи Php-Nuke. Например, менеджер фотогалереи или чат.

Инсталляция сайта занимает немного времени. По крайней мере, если у вас есть все программное обеспечение для этого, и соединение с интернетом позволяет закачать до 5 Мб на сервер хостера. Для установки Php-Nuke вам потребуется:

  • Сервер на ОС Unix с поддержкой PHP и баз данных* (MySQL, mSQL, PostgreSQL, PostgreSQL_local, ODBC, ODBC_Adabas, Sybase и Interbase) – 1 штука
  • FTP-клиент, например CuteFTP Pro 2.0 – 1 штука
  • Файл-авхив с последней версией нюки, который вы без проблем можете скачать с официального сайта - 1 штука, размером 1,3 Мб (+багфикс 9 кб)
  • Утилита для администрирования баз данных. Мы рекомендуем phpMyAdmin (урл), с помощью которого вы сможете установить нужные таблицы в своей БД.
  • Аккаунт на сервере, со всеми данными, необходимыми для инсталляции: логин на сервер, пароль на сервер, имя БД.
  • * - Наша нюка установлена на Apache Server + mySQL

Советовать сайт для хостинга мы не будем, вы сможете выбрать для себя его сами. Мы установили сайт у нас на хостинге для игрового проекта (ForZe.km.ru), который требует наличие всех выше перечисленных сервисов.

Инсталляция

Первым делом вам необходимо определиться с директорией, в которую вы будете ставить портал. Это может быть как корневой каталог www, так и другая директория, например ../www/phpnuke/

В вашем архиве есть две папки HTML (скрипты на php) и SQL (файлы, которые позволяют создать необходимые таблицы).

Берем ВСЕ файлы из каталога HTML и переносим на веб-сервер. Если вы используете «продвинутые» ftp-клиенты, то программа за вас определит режим закачки файлов – это ASCII для php-скриптов и html и Binary для графических файлов. Только убедитесь, что php-файлы заливаются на сервер верно. Затем установите багфикс для PHP-Nuke 5.4 - это два файла user.php и index.php, которые необходимо перезаписать на сервер.

Теперь вам надо изменить права доступа к некоторым файлам (permissions или chmod). О том, какие права выделяет сервер хостера, вы можете узнать в его разделе FAQ.

На MY.KM.RU на все php-файлы должны быть установлены права доступа 644 (они идут по умолчанию и позволят запускать скрипты всем пользователям сайта). И только на один файл вам необходимо установить доступ 666 - это config.php, в котором хранятся настройки вашего портала. В него необходимо внести некоторые изменения, в частности указать USERLOGIN, USERPAROL и DBNAME, которые выделены на сервере хостинга для ваших нужд:

    ####################################
    # Database & System Config
    #
    # dbhost: SQL Database Hostname
    # dbuname: SQL Username
    # dbpass: SQL Password
    # dbname: SQL Database Name
    # $prefix: Your Database table's prefix
    # $user_prefix: Your Users' Database table's prefix
    # $dbtype: Your Database Server type.
    ####################################

    $dbhost = "localhost";
    $dbuname = "USERLOGIN";
    $dbpass = "USERPAROL";
    $dbname = "DBNAME";
    $prefix = "nuke";
    $user_prefix = "nuke";
    $dbtype = "MySQL";

Закачайте этот файл на сервер.

Теперь пришло время первоначальной инсталляции базы данных mySQL. Для работы с базой данных на сервере необходимо закачать на сервер через тот же FTP программу phpMyAdmin (в нашем случае последняя версия 2.2.3). Например, в директорию: sql_admin. Затем в файле config.inc.php также необходимо изменить его часть с настройками (см. ниже), перезаписать его на сервере и дать права доступа 666.

    $cfgServers[1]['auth_type'] = 'config';
    $cfgServers[1]['user'] = 'USERLOGIN';
    $cfgServers[1]['password'] = 'USERPASSWORD';
    $cfgServers[1]['only_db'] = 'DBNAME';

Таким образом, мы установили программу myPhpAdmin на сервер и теперь ее пора запустить: http://ваше_имя.km.ru/sql_admin/index.php. Вы увидите примерно следующую картину:

Затем мы выбираем в правой колонке нашу базу (кликните по ней один раз). И видим следующую картину:

После установки необходимых таблиц базы данных мы получаем примерно следующее:

Все сложные шаги установки PHP-Nuke сделаны, запускайте в броузере:
http://ваш_адрес.km.ru/phpnuke/index.php

Изменять настройки сайта и администрировать портал можно через admin.php, используя логин: God и пароль: Password. Мы настоятельно рекомендуем при первом запуске сменить пароль для этого пользователя (http://ваш_адрес.km.ru/phpnuke/admin.php?op=mod_authors).

Если у вас не работает портал, то, видимо, вы неправильно установили права доступа к файлам, логин, пароль или имя базы данных. Будьте предельно внимательны в этих изменениях и настройках.

Если у вас сайт запустился, то после очередного изменения в настройках или при подключении модулей перестал запускаться, то скачивайте php-файл в котором найдена ошибка, открывайте в любом редакторе текстов и смотрите в чем дело... Если ничего не понимаете, пишите в форум. Мы постараемся помочь.

Ссылки по теме:

PHP-Nuke 5.4

phpMyAdmin

Security Fix for PHP-Nuke 5.4

Редактор для работы с текстом.

Источник: http://4User.ru/


PHP.Первые шаги. Действительно легкая смена дизайна

Предупреждение

Данный текст ни на что не претендует. Надеюсь, что-то из описанного поможет Вам в освоении PHP и использовании его в повседневной практике.

Сразу оговорюсь, что я не только мало смыслю в программировании вообще, но и в PHP в частности. Соответственно и статья писалась для такой же аудитории. Ламер -ламеру. Или дилетант-дилетанту, как угодно. Большинство информации можно найти в форумах или на англоязычных сайтах.

Краткая аннотация:

После прочтения статьи вы сможете использовать только один файл для внесения в него изменений дизайна и навигации. Содержимое сайта при этом не нужно будет даже трогать!

Легкая смена дизайна

Итак, у вас уже что то есть. Какой то информационный web проект. Серия статей, он-лайн книга, просто страничка. Хорошо, если у вас все в порядке с проектом на диске. Каждый раздел в своем каталоге, скрипты отлажены и жужжат, дизайн закреплен навеки.

У меня такого не было.
То есть порядок то был, а вот с дизайном - полный завал. Плюс я постоянно что то прикручиваю, балуюсь с содержимым. Что же я сделал?
Мне надо было : легко и безболезненно менять дизайн, навигацию, ссылки и баннеры, вставлять новые разделы и все это должно проходить с минимальными телодвижениями .

Я вовсю использовал SSI. Вы знаете что это такое ? Грубо говоря, у меня был шаблон хтмл, в него я вставлял меняющиеся элемнты типа меню навигации, баннеров и так далее. Но само содержание этого уже наполненного шаблона - не менялось! То есть для каждой странички в шаблон вставлял информацию, и сохранял на сервере. После этого, чтобы изменить цвет таблицы, мне пришлось бы заново делать шаблон, выдергивать информацию из старого и вставлять в новый. Можно, конечно, использовать CSS, фреймы, что там еще. Но меня все это по разным причинам не удовлетворяло.

Еще, как выход, мне мерещилось использование программы, которая заменяла бы во всех файлах одни строки на другие. Ни то, господа, ни то! Если что то сложное в плане хтмл, да еще написанного вручную, то все это адский труд. Только не подумайте, что я писал на хтмл.
Бывало, конечно, несколько строк накропаю, но я же ленивый. За меня все делало FrontPage 98. Охаиваемое всеми чудо.

Что же делать с этой кучей файлов с расширением *.shtml и невозможностью сменить дизайн так, то бы это не отозвалось болезненным перелопачиванием всей этой кучи? Я ленив, и в своих поисках я набрел на лучшее решение - PHP.
Возможность, которую он дает - один хтмл-шаблон плюс файлы только с содержимым раздела я очень быстро оценил!
Быстренько и монотонно освободив свои shtml-ки от разных табличек, вставок, картинок, и другой мутотени я вытер пот со лба. Убрал расширения файлов. Дело в том, что мой хостер хитро сделал-поздней ночью их скрипт вставляет во все файлы с расширением *.html код баннера.

Вот оно ! Стройный ряд файлов выстроился перед моим взором. Умытые, похудевшие и почистившиеся они требовали новой одежки-дизайна.
Я сваял новый шаблон: index.php3.

<HTML>
<HEAD>
</HEAD>
<BODY>
<?php
function foo ($in) {
< !--если не вызывается просто index.php3 то происходит вставка вызываемого файла-->
if ($in != "") {$out=$in;}
< !-- если происходит вызов index.php3 без имени файла, то по умолчанию, вставляется файл main-->
else {$out="main";} return $out;}?>

<!--Мой дизайн и навигация-->

<!--Вызов функции с аргументом - именем файла, запрашиваемым пользователем-->
<?php include (foo($QUERY_STRING)); ?>

<!--Мой дизайн и навигация-->

</BODY>
</HTML>

Теперь я вызываю странички так
http://myserver.ru/index.php3?news
http://myserver.ru/index.php3?links
http://myserver.ru/index.php3?about

А можно и просто
http://myserver.ru/?news
http://myserver.ru/?links
http://myserver.ru/?about

Отсутствие расширений не является критическим требованием. Если у вас набор файлов с расширениями, это не послужит препятствием. Можно вызывать для вставки любые файлы в каталоге раздела.
Например:
http://myserver.ru/index.php3?news.shtml
http://myserver.ru/index.php3?links.txt
http://myserver.ru/index.php3?about.htm

Конечно, если надо вносить изменения в содержимое (новости подновить, новый линк добавить), то приходится открывать файлы news и link и уже там что-то менять.

Минусы подхода:

1) Таги <meta> и <title> распространяются на все страницы раздела, объединенных общим index.php3.
2) Если поисковая система некорректно обрабатывает сайты, использующие PHP, то пользователь может и не найти Ваш сайт.


Евгений Молодкин, E-mail: johny_webmaster@nm.ru

Люди, используйте PHP! Часть первая

В этой статье я хочу рассказать об очень интересном способе построения сайта с помощью PHP. Этот способ в чём-то похож на использование SSI или фреймов. Итак, начнём.

Во-первых, у нас на сайте будет (фактически) всего одна (!) страница. В ней будет находиться панель навигации, место для баннера, копирайты и прочая статическая информация. Создадим её в любом редакторе (советую Macromedia Dreamweaver), назовём её index.php. Конечно, без таблиц здесь не обойтись. Рисуем таблицу (если ваш хостер вешает баннер в самом верху страницы, используйте Вариант 1, если же вы используете хостинг, где хотя бы можно изменить положение баннера, используйте Вариант 2).

Вариант 1 (1 - верхняя панель навигации, 2 - левая панель навигации, 3 - изменяющаяся часть, 4 и 5 - копирайты и все что душе угодно).

Вариант 2 (1 - место под логотип или что-нибудь ещё, 2 - место для баннера, 3 - верхняя панель навигации, 4 - левая панель навигации, 5 - изменяющаяся часть, 6 и 7 - копирайты или что-нибудь другое).

Во-вторых, определимся с изменяющимися частями. Это - контент (3 или 5) и заголовок. А теперь, о том, как нам сделать так, чтобы одна страничка в разных случаях показывала разное содержимое в изменяющихся частях. Для заголовка пишем ма-а-а-аленький скрипт на PHP:

<?php
if ($id=="") {
include ("1.ttl");
}
else {
include ("$id.ttl");
}
?>

Условие if...else здесь нужно для того, чтобы при открытии файла index.php без каких-либо параметров открывалась домашняя страничка (здесь - домашний заголовок :)). Теперь, нужно вставить этот код между тегами <TITLE> </TITLE>, сделать файлы с именем номер_страницы.ttl и написать в каждом из них заголовок страницы (номер файла с заголовком будет соответствовать номеру файла с контентом).

Для динамического изменения контента пишем почти такой же скрипт:

<?php
if ($id=="") {
include ("1.txt");
}
else {
include ("$id.txt");
}
?>

Этот код нужно вставить в ячейку с изменяющимся содержанием. Теперь создаём файлы с именем номер_страницы.txt и содержащими контент этой страницы.

Осталось только загрузить на сервер файлы: index.php, *.ttl, *.txt.

Всё, готово! Теперь все ссылки на страницы внутри сайта будут выглядеть так: /index.php?id=номер_страницы Кстати, удобно так нумеровать страницы, чтобы первая цифра числа соответствовала одному из главных разделов, вторая - подразделу, и т.д.

Работающий пример смотрите здесь.

Конечно же, некоторые Web-мастеры скажут, что всё это можно сделать с использованием базы данных. Можно. Но этот пример для НАЧИНАЮЩИХ программировать на PHP.


Работа с файлами при помощи PHP

В настоящее время существует огромное количество средств для создания по истине интерактивных веб приложений. Среди наиболее популярных стоит отметить ASP, Perl и PHP. Эти средства прочно вошли в жизнь веб-разработчика. На данный момент самым быстро развивающимся является язык PHP. Поэтому рассмотрим его возможности более подробно.

PHP является внедряемым языком сценариев. Многое из его синтаксиса заимствовано из C, Java и Perl с некоторыми, заложенными в него, уникальными особенностями. Цель языка состоит в том, чтобы позволить веб-разработчикам быстро создавать динамически генерируемые страницы.

Развитие Сети диктует свои требования по предоставлению пользователю интересующей его информации. Сайт - это не только набор веб-страничек. Это еще и средство для хранения информации, организации обработки запросов пользователя и создания адекватного ответа на пользовательский запрос.

Хранить информацию на сервере можно несколькими способами. Первый – с использованием баз данных. Очень удобный способ хранения больших объемов информации, когда необходимо организовывать выборки, сортировать информацию по различным параметрам и т. д. Если же необходимо обработать небольшой объем информации, да еще и без каких–то ухищрений (например, организовать учет посещений), то подойдет второй способ – размещение информации в файлах.

PHP предоставляет очень большой набор средств по работе с файлами и файловой системой. Рассмотрим подробнее некоторые функции для работы с файлами.

Естественно, для начала работы с файлом его надо открыть. Для этого предназначена функция fopen(). Эту функцию можно использовать для открытия любого файла в файловой системе сервера через HTTP или FTP:

int fopen(string filename, string mode);

filename – имя открываемого файла, mode – указатель на режим открытия файла. Он может принимать одно из следующих значений:

Значение | Описание
a | Открыть файл только для дополнений. Данные дописываются в конец файла.
a+ | Открыть файл для дополнения и чтения. Данные дописываются в конец файла.
r | Открыть файл только для чтения.
r+ | Открыть файл для чтения и дополнения. Данные дописываются в начало файла.
w | Открыть файл только для записи. Существующие данные будут утрачены.
w+ | Открыть файл для чтения и записи. Существующие данные будут утрачены.

При работе с двоичным файлом, необходимо указать флаг b. Однако, если между двоичными и текстовыми файлами не делается различия (как в системе Unix), то этот флаг игнорируется.

При успешном выполнении функция fopen() возвращает дескриптор файла, который представляет собой целое число. Этот дескриптор предназначен для ссылок на файл при последующих вызовах функций работы с файлами. При неудаче возвращается false. Пример:

$file_hendel = fopen("report", "a");
if (!$file_hendle)
      {
   echo("Невозможно открыть
      файл...");
   }
else {
   //
      функции работы с файлами;
   }

По завершении работы с файлом необходимо его закрыть:

int fclose(int fp)

В качестве аргумента, функция fclose() принимает дескриптор закрываемого файла. В случае успеха возвращается true, в случае неудачи – false.

Просто так файлы открывать бессмысленно. С ними надо что–то делать. Первое, что приходит на ум – вывести содержимое файла на экран. Эту операцию осуществляет функция fpassthru():

int fpassthru (int fp);

Эта функция выполняет чтение с текущей позиции в открываемом файле и до его конца, после чего она закрывает файл. В случае успеха возвращается true, в случае неудачи – false.

Может не возникнуть необходимости выводить весь файл. Возможно, нам понадобится прочесть только часть данных, для использования их на нашей странице. Для этой цели в РHP есть несколько функций.

Для чтения заданного количества символов из открываемого файла, можно воспользоваться функцией fread():

string fread(int fp, int length);

Функция читает строку длиной length символов из файла с дескриптором fp. Пример:

$file_hendel=fopen("text.txt", "r");
   if
(!$file_hendle) {
      echo("Невозможно
открыть файл...");
      }
   else
 {
      $text = fread($file_hendel, 5);
//Считывается первые 5
символов
      fclose($file_hendel);
      }

Если конец файла достигнут раньше длины length, то возвращается весь прочитанный текст.

Так же для чтения данных из файла применяются функции fgetc(), fgets() и fgetss()

string fgets(int fp, int length);
string fgetss(int fp, int length);

Функция fgetc() производит считывание одного символа.

Функция fgets() возвращает строку из (length–1) символов. Чтение завершается, если будет достигнут символ перевода строки или конец файла.

Функция fgetss() идентична fgets(), но все теги HTML удаляются из строки, но учитываются в длине строки length.

При ошибке эти функции возвращают false.

Также, для чтения содержимого файла можно использовать функцию file(), возвращающую содержимое файла в виде массива. Каждая строка файла представляется в виде элемента массива:

array file(string filename);

Функция принимает в качестве аргумента не дескриптор файла, а строку с именем файла.

Для записи в файл используются функции fputs() и fwtite().

int fputs(int fp, string string, [int length]);
int fwrite(int fp, string string, [int length]);

Если последний параметр не указан, то осуществляется запись всей строки. Пример (учет посещений с занесением данных о дате посещения и IP посетителя в файл и вывода на экран сообщения о номере посещения):

<?php
//Учет посещений
// количество посетителей будем хранить в файле report
$date=date("d M Y, H:i:s");
$ip=getenv("REMOTE_ADDR"); // опредляем IP узла
$host = gethostbyaddr($ip); // определяем имя узла по его IP
$str=(       // формируем строку,
Date – $date // для размещения ее в файле
Host – $host // учета IP – $ip
–––––––––––––––––––––");
$file_hendle = fopen("report", "a+"); //открываем файл report для добавлений,
fputs($file_hendle,$str); // записываем в него подготовленную строку и
fclose($file_hendle); // закрываем файл
// Определние и вывод порядкового номера посетителя
// количество посетителей будем хранить в файле visitors
// открываем файл visitors для перезаписи
$file_hendle = fopen("visitors", "w+");
$visitor_number = fread($file_hendle, filesize("visitors"));
$visitor_numbe++; // прибавляем еще одного посетителя,
rewind($file_hendle);
fwrite($file_hendle,$visitor_numbe); // переписываем файл visitors и
fclose($file_hendle); // закрываем файл
echo ("Поздравляем, вы $visitor_numbe посетитель!");
?>

Существует также несколько функций для управления текущей позицией в файле. Они облегчают свободное перемещение по файлу.

Функция rewind() устанавливает текущую позицию в начало файла, дескриптор которого она принимает в качестве аргумента.

Может возникнуть необходимость определить текущее положение в файле. Для этой цели служит функция ftell()

int ftell(int fp);

С помощью функции fseek() можно переместиться в заданную позицию.

int fseek(int fp, int offset [, int whence]);

Основными аргументами функции являются дескриптор файла и значение заданной позиции от начала файла. Например, с помощь функции ftell() можно организовать перемещение в заданную позицию:

fseek($fp, ftell($fp)+10); // переход на 10 позиций вперед от текущей

Но этого же эффекта в PHP4 можно добиться без использования функции ftell(), так как в функции fseek() появился необязательный аргумент, который определяет способ перемещения на заданную позицию:
SEEK_SET – отсчитывает значение от начала файла (по умолчанию);
SEEK_CUR – отсчитывает значение от текущей позиции;
SEEK_END – прибавляет значение offset к концу файла.

Тот же пример в PHP4 примет вид:

fseek($fp, 10, SEEK_CUR);

Часто возникают ситуации, когда надо проверить положение указателя относительно конца файла. Для этого применяется функция feof(), которая возвращает true, если достигнут конец файла и false, если конец файла не достигнут.

Возможности PHP по работе с файлами не ограничиваются приведенными здесь функциями. С полным описанием функций для работы с файловой системой можно ознакомится на официальном сайте PHP в разделе PHP:Manual:Filesystem functions.


HotMail своими руками, или Что может PH

Виктор Хименко, 15.02.1999, Мир ПК, #02/1999

В этой статье я хотел бы продемонстрировать, что создание работоспособных и полезных динамических Web-узлов вовсе не такая сложная задача, как может показаться при чтении текстов, описывающих интерфейс CGI. На самом деле подобная работа (по крайней мере, при использовании Linux) больше всего напоминает игру The Incredible Machines, где нужно кремнем высечь искру, чтобы свет упал на солнечную батарею, от которой срабатывает сверхсовременный компьютер. Здесь тоже все, как правило, собирается из компонентов, которые оказались под рукой.

В качестве примера мы рассмотрим создание почтовой службы на Web-сервере - WebMail - на основе языка PHP3 с максимальным использованием готовых компонентов. За кадром останутся создание новых пользователей, их регистрация в базе данных и т. п. Наша почта, кроме того, не будет обрабатывать письма с вложениями и в кодировках, отличных от KOI8-R, поддерживать записные книжки и т. п. - все это лишь увеличило бы размеры сценариев, не дав ничего принципиально нового.

Компоненты

Вначале о "готовых компонентах". Я уже упомянул о том, что все описанное ниже рассчитано на использование Linux. Однако существующие дистрибутивы этой ОС настолько различаются по комплектации, что вряд ли удастся построить пример, который годился бы для любой версии. Поэтому я ограничусь версией, с которой лучше всего знаком, - KSI-Linux 2.0 (http://www.ksi-linux.com). Если у вас другой вариант Linux, например RedHat 5.2 или Debian 2.0, то вам, скорее всего, потребуется получить некоторые компоненты из Internet или перекомпилировать уже имеющиеся.

Нам понадобятся Web-сервер Russian Apache 1.3.x rus/PL 27.4, PHP 3.0.6 с поддержкой протокола IMAP4r1 и почтовый сервер IMAP4r1. Благодаря Russian Apache мы будем, по крайней мере отчасти, избавлены от проблем с кодировками: независимо от кодировки, используемой клиентом, данные на сервер всегда будут посылаться в KOI8-R (это настройка Russian Apache по умолчанию). Сервер IMAP4r1 позволит нам манипулировать почтовым ящиком, не описывая в явной форме права доступа (связываясь с этим сервером, вы указываете свое имя и пароль, и он сам решает все проблемы с правами). И наконец, PHP 3.0.6 с поддержкой протокола IMAP4r1 даст возможность работать с сервером IMAP4r1, не реализуя самостоятельно соответствующий протокол, который весьма и весьма нетривиален.

Здесь многие зададут вопрос: а почему не perl? Дело в том, что, хотя язык perl - стандартная "рабочая лошадка" для создания Web-узлов, у него есть определенные недостатки. Интерпретатор perl существенно сложнее интерпретатора PHP и требует для работы больше ресурсов компьютера. Кроме того, это не интерпретатор в точном смысле слова: он компилирует программу в специализированный псевдокод, который затем немедленно исполняется. Если в программе есть циклы, такой подход может дать существенный выигрыш, но если нет (как это часто бывает в простых сценариях для Web-сервера - например, во всей нашей реализации WebMail будет всего один цикл), накладные расходы не окупаются. Применение mod_perl - дополнительного модуля Apache - позволяет избежать многократной перекомпиляции сценариев, но при этом к памяти сервера предъявляются еще более высокие требования.

Коротко о PHP

Теперь несколько слов о том, что же такое PHP. Это интерпретируемый язык для создания активных Web-страниц. Программа на PHP, подобно тексту на JavaScript, VBScript или ASP, вставляется в HTML-файл. Начало и конец программы отмечаются специальными скобками <?PHP и ?>. Текст вне этих скобок PHP не интерпретирует: он передается Web-браузеру "как есть". В листинге 1 приведена реализация на PHP "вечного" примера - счетчика. Как видите, это совершенно обычный HTML-файл, однако в том месте, где должно стоять количество посещений, стоит сценарий на PHP3, который в качестве результата своей работы выводит число посещений страницы1.

Синтаксис PHP основан на синтаксисе языков Си, Java и perl и довольно подробно описан в руководстве, которое входит в комплект поставки (его также можно взять на узле http://www.php.net/). Способы заставить сервер правильно реагировать на HTML-файлы со вставками на PHP, вообще говоря, различны для разных серверов, но чаще всего бывает достаточно дать имени файла расширение .php3.

Итак, мы хотели бы иметь возможность читать и отправлять почту с помощью Web-браузера. Видимо, будет разумно сделать интерфейс похожим, скажем, на Netscape Messenger: окно разделено по горизонтали на две части, в верхней находится список писем в нашем почтовом ящике на сервере, в нижней - текущее письмо. Но перед тем как показать пользователю HTML-файл с описанием фреймов, мы потребуем от него ввести свое имя и пароль (при неправильно введенном пароле он получит файл, содержащий сообщение об ошибке). Эту функцию будет осуществлять файл index.php3, показанный в листинге 2. Давайте посмотрим на него поближе.

Прежде всего стоит обратить внимание на то, что скобка <?PHP, открывающая PHP-сценарий, стоит в самом начале файла. Это не случайно. Дело в том, что не нужно сообщать браузеру о том, что документ состоит из нескольких фреймов, пока пользователь не введет правильные имя и пароль. Чтобы запросить пароль, мы меняем "ответ сервера" с обычного "200 OK" на "401 Auth Required"2. Это очень просто: специально для подобных случаев в PHP предусмотрена функция Header(). Но эта функция работает только при условии, что перед ее вызовом вывод документа еще не был начат, и следовательно, скобка <?PHP должна стоять в самом начале файла...

Дальнейшее очевидно: мы смотрим на введенное пользователем имя и пароль, пытаемся связаться с сервером IMAP4r1 и, если все прошло успешно, просто выдаем информацию о наборе фреймов. Однако теперь во все сценарии в том подкаталоге, где размещается наш стартовый файл index.php3, будет передаваться информация об имени и пароле!3

Заметим также, что перед именем функции imap_open стоит символ "@". Он означает, что сообщения о возможных ошибках при работе функции должны не выводиться в текст на HTML (поведение PHP по умолчанию), а сохраняться в специальной переменной. Это необходимо для того, чтобы воспользоваться функцией Header(): она не будет работать, если в тело документа уже выведен какой бы то ни было текст, в том числе и сообщение об ошибке.

Другие файлы

Теперь нам нужно создать файлы top.php3 и main.php3, на которые имеются ссылки в index.php3. Начнем с top.php3 (листинг 3). В нем мы строим таблицу, в которой каждая строка соответствует одному письму и содержит его порядковый номер, тему, имя (адрес) отправителя и дату отправки. Вся информация извлекается из соответствующих полей заголовка письма.

При оформлении ссылок (HREF) мы должны не забыть передать номер письма (как при работе с обычным CGI-сценарием). Файл main.php3 (листинг 4) проверяет, установлена ли переменная $mail. Если нет, то выводится только надпись New message с соответствующей ссылкой, а если да, добавляются еще две ссылки - Reply и Delete. Кроме того, ссылки, встречающиеся в тексте письма, заменяются на ссылки HTML. Файлы mail.php3, del.php3 и send.php3 (листинги 5-7) устроены предельно просто, однако, так как файлы del.php3 и send.php3 содержат вызовы функции Header(), они начинаются со скобки <?PHP. На сей раз эти вызовы нужны для того, чтобы сообщение об успешной посылке или удалении письма заменилось на основное окно автоматически, без каких бы то ни было действий со стороны пользователя.

Чего мы не сделали

Вот и все. Служба WebMail готова (см. рисунок). Как несложно заметить, мы всего лишь соединили готовые части - все наши шесть файлов не насчитывают и двух сотен строк - и получили почти настоящую почтовую программу. Конечно, с ней связаны и некоторые проблемы. Например, такие.

1. Что будет, если с помощью нашей WebMail попробовать читать почту одновременно с двух компьютеров? При удалении письма на одном компьютере нумерация "съедет", и на втором начнут происходить весьма неприятные вещи.
2. Как уже было замечено, на сервере с не полностью контролируемым содержанием использование нашей программы может привести к попаданию паролей в нечистые руки.
3. Нет поддержки кодировок, отличных от KOI8-R, для почты (при том, что для Web-браузера благодаря Russian Apache поддерживаются все распространенные кодировки).
4. Нет поддержки вложений.
5. Нет записной книжки.
6. Нет поддержки папок.

Впрочем, мы и не ставили себе целью создать программу, способную сравниться с Eudora или Pegasus (но, кстати, программа Imap webMail Program - см. http://web.horde.org/imp/ - очень близка к этому).

Сделаем еще несколько замечаний по поводу возможных решений первой и второй проблемы. Эти проблемы связаны с обеспечением безопасности, а значит, требуют особого внимания. Для решения первой проблемы можно передавать в дополнение к номеру письма еще и идентификатор сообщения (MessageID); это, однако, повлечет существенное усложнение программы, так как нужно будет организовать подробное "разбирательство" в случае несовпадения идентификаторов, а также корректное обновление списка писем.

Вторая проблема решается путем добавления еще одной формы на входе и передачи имени пользователя и пароля от сценария к сценарию через URL - так, как сейчас передается номер письма. Но тогда пароль будет появляться в адресной строке браузера. С этим можно бороться двумя способами - либо зашифровывая пароль перед посылкой и расшифровывая при получении, либо создав еще два фрейма: первый не используется никак (или в нем размещается реклама, что, в общем, то же самое), во втором происходит вся работа. Можно и скомбинировать названные способы. Дерзайте!

ЛИСТИНГ 1 Файл counter.php3 (счетчик числа посещений Web-страницы)
<html>
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
vlink="#800080" alink="#FF0000">
<p> Число посещениий: <?PHP
    $filename = "counter.dat";
    $fp = @fopen($filename,"r");
    if ($fp) {
        $counter=fgets($fp,10);
        fclose($fp);
    } else {
        $counter=0;
    }
    $counter++;
    print $counter;
    $fp = fopen($filename,"w");
    if ($fp) {
        $counter=fputs($fp,$counter);
        fclose($fp);
    }
?>
</body>
</html>

ЛИСТИНГ 2 Файл index.php3 (идентификация пользователя, установление контакта с почтовым
 сервером и создание набора фреймов для вывода списка писем и текста текущего письма)
<?PHP
  $REALM =  "Web mail";
  $POPSERVER =  ‘127.0.0.1’;
  $LOGERRORS = 1;
  if(!isset($PHP_AUTH_USER)):
    Header( "WWW-Authenticate: Basic realm=\"$REALM\"");
    Header( "HTTP/1.0 401 Unauthorized");
    echo  "<H1>Authorization Required</H1>\n";
    exit;
  else:
    if(!($imap_stream=@imap_open("{127.0.0.1:143}Inbox","$PHP_
AUTH_USER","$PHP_AUTH_PW",OP_READONLY))):
      Header( "WWW-Authenticate: Basic realm=\"$REALM\"");
      Header( "HTTP/1.0 401 Auth Required");
      echo  "<H1>Authorization Required</H1>\n";
      exit;
    else:
      imap_close($imap_stream); ?>
<html>
<frameset border="0" framespacing="-2" rows="20%,80%">
  <frame src="top.php3" name="top" marginwidth="1"
marginheight="1" framespacing="0">
  <frame src="main.php3" name="main" marginwidth="1"
marginheight="1" framespacing="0">
</frameset>
<noframes>
<body>
  Sorry, but your browser does not support frames...<br>
</body>
</noframes>
</html>
<?PHP       endif;
            endif;
?>

ЛИСТИНГ 3 Файл top.php3 (формирование списка писем)
<html>
<body bgcolor="#C04040" text="#FFFFFF" link="#0000FF"
vlink="#800080" alink="#FF0000">
<BASE TARGET="main">
<?PHP
  $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER",
"$PHP_AUTH_PW",OP_READONLY);
  $inbox=imap_mailboxmsginfo($imap_stream);
 ?>
<CENTER><table border=3 width="100%">
<tr><th>NN</th><th>Subject</th><th>From</th>

<th>Date</th></tr>
<tr><td>
<?PHP
  for($i=1;$i<=$inbox->Nmsgs;$i++):
     $header=imap_header($imap_stream,$i,300,300,0);
     echo "<tr><td><B><a href=main.php3?mail=".$i.
          ">".$i.
          "</a></B></td><td><a href=main.php3?mail=".$i.
          ">".$header->Subject.
          "</a></td><td><a href=main.php3?mail=".$i.
          ">".$header->fromaddress.
          "</a></td><td><a href=main.php3?mail=".$i.
          ">".$header->Date.
          "</a></td></tr>";
  endfor;
  imap_close($imap_stream);
?>
</table>
</CENTER>
</body>
</html>

ЛИСТИНГ 4 Файл main.php3 (проверка наличия писем и вывод кнопок)
<html>
<body bgcolor="#408080" text="#FFFFFF" link="#0000FF"
vlink="#800080" alink="#FF0000">
<BASE TARGET="main">
<a href=mail.php3>New message</a> <?PHP if (isset($mail) &&
($mail>=1)):?>| <a href=mail.php3?mail=<?PHP echo $mail;?>>
Reply</a>| <a href=del.php3?mail=<?PHP echo $mail;?>target=
_top>Delete</a><?PHP endif;?><br><br>
<?PHP
if(isset($mail) && ($mail>=1)):
  $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER",
"$PHP_AUTH_PW",OP_READONLY);
  $inbox=imap_mailboxmsginfo($imap_stream);
  $body=imap_fetchbody($imap_stream,$mail,1,0);
  print(nl2br(eregi_replace( "(http|https|ftp)://([-=%_
a-zA-Z0-9./~?:]+)", "<a href=\"\\1://\\2\" target=\"_blank\
">\\1://\\2</a>", htmlspecialchars($body))));
  imap_close($imap_stream);
endif;
?>
</body>
</html>

ЛИСТИНГ 5 Файл mail.php3 (создание письма)
<html>
<body bgcolor="#408080" text="#FFFFFF" link="#0000FF"
vlink="#800080" alink="#FF0000">
<BASE TARGET="main">
<?PHP
if (isset($mail) && ($mail>=1)):
    $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER",
"$PHP_AUTH_PW",OP_READONLY);
    $header=imap_header($imap_stream,$mail,300,300,0);
endif;
?>
<FORM ACTION=’send.php3’ METHOD=’POST’>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
   <TR>
      <TD class=light WIDTH="150">
         <B><b>Your name :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="sendername" VALUE="<?PHP
echo $sendername;?>" SIZE=60 maxlength=70>
      </TD></TR>
   <TR>
      <TD class=light WIDTH="150">
        <B><b>From :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="sender" VALUE="<?PHP echo
$PHP_AUTH_USER."@host.some_domain.com";?>" SIZE=60
maxlength=70>
</TD></TR><TR><TD class=light WIDTH="150">
        <B><b>Subject :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="subject" VALUE="<?PHP if
(isset($mail) && ($mail>=1)):?>Re: <?PHP echo
eregi_replace("\"","&#34;",$header->Subject); endif;?>" SIZE=60
maxlength=70>
      </TD></TR>
      <TR>
    <TD class=light WIDTH="150">
         <B><b>To :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="mailto" VALUE="<?PHP if
(isset($mail) && ($mail>=1)): echo eregi_replace

 ("\"","&#34;",$header->fromaddress); endif;?>" SIZE=60
maxlength=70>
      </TD></TR>
      <TR>
    <TD class=light WIDTH="150">
         <B>Message body :
      </TD><TD COLSPAN=2 class=light>
         <textarea name="text" rows=15 cols=59><?PHP if
(isset($mail) && ($mail>=1)): echo "&gt; ".eregi_replace
("\n","\n&gt; ",htmlspecialchars(imap_fetchbody
($imap_stream,$mail,1,0))); endif;?></textarea>
<center><input type=submit value="Send"></center><br>
</TD></TR>
</TABLE>
</form>
</body>
</html>
<?PHP if (isset($mail) && ($mail>=1)):imap_close($imap_stream);endif; ?>

ЛИСТИНГ 6 Файл del.php (удаление письма)
<html>
<body bgcolor="#408080" text="#FFFFFF" link="#0000FF"
vlink="#800080" alink="#FF0000">
<BASE TARGET="main">
<?PHP
if (isset($mail) && ($mail>=1)):
    $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER",
"$PHP_AUTH_PW",OP_READONLY);
    $header=imap_header($imap_stream,$mail,300,300,0);
endif;
?>
<FORM ACTION=’send.php3’ METHOD=’POST’>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
   <TR>
      <TD class=light WIDTH="150">
         <B><b>Your name :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="sendername" VALUE="<?PHP
echo $sendername;?>" SIZE=60 maxlength=70>
      </TD></TR>
   <TR>
      <TD class=light WIDTH="150">
        <B><b>From :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="sender" VALUE="<?PHP echo
$PHP_AUTH_USER."@host.some_domain.com";?>" SIZE=60 maxlength=70>
      </TD></TR>
   <TR>
      <TD class=light WIDTH="150">
        <B><b>Subject :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="subject" VALUE="<?PHP if
(isset($mail) && ($mail>=1)):?>Re: <?PHP echo eregi_replace
("\"","&#34;",$header->Subject); endif;?>" SIZE=60 maxlength=70>
      </TD></TR>
      <TR>
    <TD class=light WIDTH="150">
         <B><b>To :</b></B>
      </TD><TD COLSPAN=2 class=light>
         <INPUT TYPE="text" NAME="mailto" VALUE="<?PHP if
(isset($mail) && ($mail>=1)): echo eregi_replace
("\"","&#34;",$header->fromaddress); endif;?>" SIZE=60 maxlength=70>
      </TD></TR>
      <TR>
    <TD class=light WIDTH="150">
         <B>Message body :
      </TD><TD COLSPAN=2 class=light>
         <textarea name="text" rows=15 cols=59><?PHP if
(isset($mail) && ($mail>=1)): echo "&gt; ".eregi_replace
("\n","\n&gt; ",htmlspecialchars(imap_fetchbody
($imap_stream,$mail,1,0))); endif;?></textarea>
<center><input type=submit value="Send"></center><br>
</TD></TR>
</TABLE>
</form>
</body>
</html>
<?PHP if (isset($mail) && ($mail>=1)):imap_close($imap_stream);endif; ?>

ЛИСТИНГ 7 Файл send.php3 (отправка письма)
<?PHP
    Header("Refresh: 5;url=main.php3");
?>
<html>
<body bgcolor="#408080" text="#FFFFFF" link="#0000FF"
vlink="#800080" alink="#FF0000">
<BASE TARGET="main">
<?PHP
mail($mailto,$subject,$text,"From: $sendername <$sender>\n

Content-Type: text/plain; charset=KOI8-R");
?>
Message was succesfully sent.
</body>
</html>

1 Сценарий намеренно предельно упрощен: он не заботится о блокировке файлов, не обрабатывает ошибки записи на диск и т. п. Заметим, что наш счетчик, в отличие от большинства других, написан без использования тега <IMG>. Это позволяет сократить трафик и решает проблему неграфических браузеров (например, браузеров для слепых), но может создать проблемы, если нам нужен единый счетчик для нескольких "зеркал" основного узла. "Традиционная" реализация счетчика в PHP также не представляет проблемы, поскольку он имеет множество функций для порождения GIF-файлов (включая даже получение красивых надписей, выполненных шрифтами TrueType).

2 Число 401 взято не с потолка, а из описания протокола HTTP.

3 К сожалению, если в каком-либо другом подкаталоге указать realm="Web mail", то находящиеся в нем сценарии также получат соответствующую информацию. Поэтому данный метод неприемлем, если вы не можете контролировать содержимое всего узла.

Ссылки

Apache: http://www.apache.org/

Russian Apache: http://apache.lexa.ru/

PHP3: http://www.php.net/

IMAP4r1 library and daemons: http://www.cac.washington.edu/imap/

IMP: http://web.horde.org/imp/


Руководство по PHP

Preface

PHP Версии 3.0 - язык написания сценариев, внедренный в HTML. Многое из синтаксиса заимствовано из C, Java и Perl, с добавлением специфичных для PHP возможностей. Задача языка состоит в том, чтобы дать возможность Web-разработчикам легко и быстро создавать динамично изменяемые html-страницы.

Об этом руководстве

Это руководство написано в SGML при помощи DocBook DTD, с использованием DSSSL (Стиль Документа и Язык Спецификаций Семантики) при форматировании. Инструментальные средства, используемые для форматирования HTML, TeX и RTF версий - Jade, написанный Джеймсом Кларком и The Modular DocBook Stylesheets, созданные Норманом Валшом. Структура документации PHP3 была разработана Стигом СЈзером Баккеном.

Глава 1. Введение в PHP3

Что такое PHP3?

PHP версии 3.0 - язык описания сценариев, выполняемых на сервере, встроенный в HTML.

Что может делать PHP3?

Возможно самая сильная и значимая возможность в PHP3 - уровень интеграции с базами данных. Написание веб-страницы работающей с базой данных невероятно проста. В настоящее временя поддерживаются следующие базы данных:

Oracle
Adabas D
Sybase
FilePro
mSQL
Velocis
MySQL
Informix
Solid
dBase
ODBC
Unix dbm
PostgreSQL

Краткая История PHP

PHP был задуман где-то в конце 1994 года Расмусом Ледорфом(Rasmus Lerdorf). Ранние невыпущенные версии использовались на его домашней странице для того, чтобы следить за тем кто просматривал его интерактивное резюме. Первая используемая версия cтала доступна где-то в начале 1995 и была известна как Personal Home Page Tools. Она состояла из очень упрощенного движка синтаксического анализатора, который понимал только несколько специальных макрокоманд и ряд утилит, которые затем были в общем использовании на домашних страницах. Гостевые книги, счетчики и некоторые другие дополнения.

Довольно трудно дать какую-либо жесткую статистику, но отмечено, что к 1996 г. PHP/FI был использован по крайней мере на 15,000 веб-сайтах во всем мире. В середине 1997г. эта цифра выросла до более чем 50,000. В середине 1997г. также наблюдалось изменение в разработке PHP. Из частного любимого проекта Расмуса, которому способствовала горстка людей , это превратилось в намного более организованную рабочую группу. Синтаксический анализатор был заново переписан Зевом Сураски(Zeev Suraski) и Анди Гутмансом(Andi Gutmans), и этот новый синтаксический анализатор стал основой для PHP Версии 3.

Сегодня ( в середине -1998г.) как PHP/FI так и PHP3 поставляется с рядом коммерческих продуктов типа C2's StrongHold web server и RedHat Linux и консервативной оценкой, основанной на экстрaполяции чисел, предоставленных NetCraft было бы то, что PHP используется на 150,000 cайтах во всем мире. В перспективе, их больше чем сайтов, запущенных на Netscape's flagship Enterprise server в Интернете.


Глава 2. Возможности PHP3

Содержание:

    1. HTTP-аутификация средствами PHP
    2. Создание GIF-файлов с помощью PHP
    3. Поддержка file upload
    4. Поддержка HTTP cookie
    5. Поддержка баз данных
    6. Регулярные выражения
    7. Обработка ошибок
    8. PHP source viewer

HTTP-аутификация средствами PHP

HTTP аутификация в PHP доступна только при использовании модуля Apache. В модуле Apache PHP-скрипт, может использовать функцию Header() для отправки сообщения "Authentication Required" браузеру клиента, вызвав тем самым окно диалога Username/Password. Как только пользователь заполняет поля username и password, URL содержащий PHP-скрипт будет вызван заново с переменными $PHP_AUTH_USER, $PHP_AUTH_PW и $PHP_AUTH_TYPE содержащими введенную информацию. В данном случае обеспечивается только "Основная" аутификация.

Фрагмент примера сценария, который производит аутентификацию клиента на странице, должен быть следующим:

Пример 2-1. Пример HTTP аутификации

<?php
  if(!isset($PHP_AUTH_USER)) {
    Header("WWW-Authenticate: Basic realm=\"My Realm\"");
    Header("HTTP/1.0 401 Unauthorized");
    echo "Text to send if user hits Cancel button\n";
    exit;
  } else {
    echo "Hello $PHP_AUTH_USER.<P>";
    echo "You entered $PHP_AUTH_PW as your password.<P>";
  }
?>

Вместо просто распечатывания $PHP_AUTH_USER и $PHP_AUTH_PW, Вы вероятно хотели бы проверить имя_пользователя и пароль для проверки правильности. Возможно, посылая запрос к базе данных, или, ища пользователя в dbm файле.

Будьте внимательны при использовании браузера Internet Explorer. Он весьма придирчив к порядку заголовков. Отправка заголовка WWW-Authenticate перед заголовком HTTP/1.0 401 возможно даст аутификацию в любом случае.

Чтобы предотвратить от записи кем - то сценарий , который определяет пароль для страницы, которая была опознана через традиционный внешний механизм, PHP_AUTH переменные не будут установлены, если допускается внешнее установление подлинности для той специфической страницы. В этом случае может быть использована переменная $REMOTE_USER чтобы идентифицировать внешне-опознанного пользователя.

Обратите внимание, однако, что вышеупомянутое не защищает от кого - то, кто может управлять не-аутифицированным URL используя перехваченный пароль из аутифицированных URL на том же самом сервере.

И Netscape и Internet Explorer очистит локальный кэш окна аутификации после получения ответа сервера 401. Это эффективно как мера отключения пользователей("log out"), вынуждающая их повторно ввести их username и пароль. Некоторые используют это для отключения пользователя по истечении интервала времени("time out"), или обеспечивают кнопку "Log Out". Эти методы не требуются в соответствии с Основным стандартом аутификации HTTP , так что Вы никогда не должны зависеть от этого. Тестирование с Lynx показало, что Lynx не очищает информацию аутификации с 401 ответом сервера, так что переход обратно и затем вперед снова откроет ресурс (пока требования удостоверения личности не изменились).

Также обратите внимание, что это не работает при использовании сервера Microsoft's IIS и CGI версии PHP из-за ограничений IIS.

Создание GIF-файлов с помощью PHP

PHP не ограничен созданием только HTML вывода. Он может также использоваться для создания файлов GIF, или даже более удобные потоки изображений GIF. Для этого вам надо скомпилировать PHP с библиотекой функций изображения - GD.

Пример 2-2. Создание GIF-файлов с помощью PHP

<?php
    Header("Content-type: image/gif");
    $string=implode($argv," ");
    $im = imagecreatefromgif("images/button1.gif");
    $orange = ImageColorAllocate($im, 220, 210, 60);
    $px = (imagesx($im)-7.5*strlen($string))/2;
    ImageString($im,3,$px,9,$string,$orange);
    ImageGif($im);
    ImageDestroy($im);
?>

Этот пример вызывается со страницы тегом: <img src="button.php3?text"> Вышеупомянутый скрипт button.php3 берет строку "text", накладывает сверху на основное изображение, которым в этом случае является " images/button1.gif " и выводит возникающее в результате изображение. Это - очень удобный способ не рисовать новые изображения кнопки, каждый раз, когда вы хотите изменить текст кнопки. Этим методом они будут динамически сгенерированы.

Поддержка file upload

PHP может принимать файлы, загруженные из любого браузера, отвечающего стандартам RFC-1867 (которыми являются, например, Netscape Navigator 3 или cтарше, Microsoft Internet Explorer 3 с исправлениями от Microsoft, или cтарше). Эта возможность позволяет людям загружать файлы. С PHP-аутификацией и функциями манипулирования файлами, вы имеете полный контроль над тем, кому позволять загружать файлы и что должно быть выполнено с файлом, если он был загружен.

Экран загрузки файла может быть организован созданием специальной формы, которая выглядит примерно так:

Пример 2-3. Форма загрузки файла

<FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD=POST>
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000">
Send this file: <INPUT NAME="userfile" TYPE="file">
<INPUT TYPE="submit" VALUE="Send File">
</FORM>

_URL_ должен указать на php html файл. Cкрытое поле MAX_FILE_SIZE должно предшествовать полю ввода файла и означает максимально допустимый размер файла. Значение определяется в байтах. Для этого файла при успешной загрузке будут определены следующие переменные:

$userfile - Временное имя файла под которым загруженный файл загружается в машину сервера.

$userfile_name - Исходное имя файла в системе отправителя.

$userfile_size - Размер загруженного файла в байтах.

$userfile_type - Тип MIME файла, если броузер предоставил эту информацию. Например может быть "image/gif".

Обратите внимание, что компонент вышеупомянутых переменных "$userfile" - это любое значение поля Name тега INPUT c TYPE=file обозначенное в форме загрузки. В приведенном выше примере формы загрузки мы назвали его "userfile".

По умолчанию файлы будут сохранены в заданном по умолчанию временном каталоге сервера. Его можно изменить, установкой переменной среды TMPDIR в среде, в которой PHP выполняется. Хотя, использование при ее установке обращения PutEnv() изнутри сценария PHP не будет работать.

Скрипт PHP, который получает загруженный файл, должен определить, что должно быть выполнено с загруженным файлом. Вы можете, например, использовать переменную $file_size, чтобы отбросить любые файлы, которые являются или слишком маленькими или слишком большими. Вы могли бы использовать переменную $file_type, чтобы отбросить любые файлы, которые не соответствуют некоторым критериям типа.В любом случае, вы должны или удалить файл из временного каталога или переместить его в другое место.
Файл будет удален из временного каталога в конце запроса, если он не перемещен или переименован.

Пожалуйста обратите внимание, что вебсервер CERN httpd, кажется, удаляет все начинающееся с первого пробела в заголовке content-type mime, полученном от клиента. Пока дело обстоит так, CERN httpd не будет поддерживать возможность загрузки файла.

Поддержка HTTP cookie

PHP поддерживает HTTP cookies. Cookies - механизм для сохранения данных в удаленном браузере и, таким образом, - трэкинг или идентификация пользователей. Вы можете устанавливать файлы cookie используя функцию setcookie(). Cookies - часть HTTP заголовка, так что функция SetCookie() должна вызваться прежде чем браузеру послан какая-нибудь информация для вывода. Это - то же самое ограничение, которое касается и функции Header().

Любой cookie, посланный Вам от клиента будет автоматически превращен в переменную PHP точно так же как данные методов GET и POST. Если вы желаете назначить множественные значения одиночному cookie - просто добавьте [] к имени cookie. Для более подробной информации см. функцию setcookie ().

Поддержка баз данных

PHP поддерживает ряд различных баз данных, и в режиме работы в собственной системе команд и через ODBC, включая:

Adabas D
MySQL
dBase
Oracle
Empress
PostgreSQL
FilePro
Solid
Informix
Sybase
InterBase
Velocis
mSQL
Unix dbm

Регулярные выражения

Регулярные выражения используются для сложного манипулирования строками в PHP. Функции, которые поддерживают регулярные выражения:

ereg()
ereg_replace()
eregi()
eregi_replace()
split()

Все эти функции принимают строку регулярного выражения как их первый параметр. PHP использует расширенные регулярные выражения POSIX как определено в POSIX 1003.2. Для полного описания регулярных выражений POSIX см.соответствующие разделы руководства (regex), в каталоге regex дистрибутива PHP.

Example 2-4. Пример регулярных выражений

ereg("abc",$string);
/* Возвращает 'истина', если "abc"
   найдено в строке $string. */
ereg("^abc",$string);
/* Возвращает 'истина', если "abc"
   найдено в начале строки $string. */
ereg("abc$",$string);
/*  Возвращает 'истина', если "abc"
   найдено в конце строки $string. */
eregi("(ozilla.[23]|MSIE.3)",$HTTP_USER_AGENT);
/*  Возвращает 'истина', если браузер клиента
   - Netscape 2, 3 или MSIE 3. */
ereg("([[:alnum:]]+) ([[:alnum:]]+) ([[:alnum:]]+)",
     $string,$regs);
/* Помещает три слова - $regs[1], $regs[2] и $regs[3], разделенные пробелом. */
ereg_replace("^","<BR>",$string);
/* Устанавливает тег <BR> в начало строки $string. */
ereg_replace("$","<BR>",$string);
/* Устанавливает тег <BR> в конец строки $string. */
ereg_replace("\n","",$string);
/* Отсекает символ "возврат каретки" в строке $string. */

Обработка ошибок

В PHP есть 4 типа ошибок и предупреждений.Это:

1 - Нормальные Ошибки Функции(Normal Function Errors)

2 - Нормальные Предупреждения(Normal Warnings)

4 - Ошибки Синтаксического Анализатора(Parser Errors)

8 - Уведомления(Notices) : предупреждения, которые Вы можете проигнорировать но, которые могут подразумевать баги в вашем коде

Эти 4 типа комбинируются при определении ошибки, сообщая уровень.Ошибка по умолчанию, возвращает уровень 7, который является комбинацией 1 + 2 + 4, или все ошибки за исключением примечаний. Этот уровень может быть изменен в файле php3.ini директивой error_reporting. Он также может быть установлен в вашем файле Apache httpd.conf директивой php3_error_reporting, или же это может быть произведено во времени выполнения сценария, с использованием функции error_reporting().

Все выражения PHP могут также вызываться с префиксом "@", который выключает сообщение об ошибке,специфичное для этого выражения. Если ошибка произошла во время выполнения такого выражения, и допускается возможность track_errors, Вы можете найти сообщения об ошибках в глобальной переменной $php_errormsg.


Глава 3. Установка

Эта глава является руководством по конфигурации и установке PHP3. Требуемые знания и программное обеспечение:

  • базовые навыки работы с UNIX (на уровне выполнения команды "make" и компилятора С);

  • компилятор ANSI C;

  • web server (очевидно);

Установка из исходных кодов на UNIX:

Загрузка исходных кодов:

Исходные коды последней версии можно найти по адресу: http://www.php.net

.
Инструкции по быстрой установке (версия модуля Apache):

1. gunzip apache_1.3.x.tar.gz
2. tar xvf apache_1.3.x.tar
3. gunzip php-3.0.x.tar.gz
4. tar xvf php-3.0.x.tar
5. cd apache_1.3.x
6. ./configure --prefix=/www
7. cd ../php-3.0.x
8. ./configure --with-mysql --with-apache=../apache_1.3.x --enable-track-vars
9. make
10. make install
11. cd ../apache_1.3.x
12. ./configure --prefix=/www --activate-module=src/modules/php3/libphp3.a
13. make
14. make install

Вместо этих шагов Вы можете простоскопировать бинарный файл httpd поверх вашего существующего бинарного файла.
Перед этим убедитесь, что Вы выключили свой сервер.

15. cd ../php-3.0.x
16. cp php3.ini-dist /usr/local/lib/php3.ini

Вы можете отредактировать файл /usr/local/lib/php3.ini для установления опций PHP.
Если Вы предпочитаете поместить этот файл в другое место,
то используйте --with-config-file=/path в шаге 8.

17. Отредактируйте Ваш файл httpd.conf или srm.conf и добавьте:

AddType application/x-httpd-php3 .php3

Вы можете выбрать здесь любое расширение по Вашему желанию.
В данном случае мы просто рекомендуем выбрать .php3.

18. Используйте Вашу обычную процедуру для запуска сервера Apache.
(Вы должны остановить и перезапустить сервер, а не просто перезагрузить сервер
с использованием сигнала HUP или USR1).

Конфигурация:

Имеется два пути конфигурирования PHP3.

  • используйте скрипт "setup", который поставляется с PHP3. Этот скрипт задает Вам ряд вопросов (практически совпадающих со сценарием "install" PHP/FI 2.0) и в конце запускает "configure". Для запуска этого скрипта наберите ./setup.

    Этот сценарий также создает файл, называемый "do-conf", который содержит опции, установленные при конфигурации. Вы можете редактировать этот файл для изменения некоторых опций без перезапуска "setup". Тогда выполните ./do-conf и конфигурация запустится с новыми параметрами.

  • выполните конфигурацию вручную. Для просмотра параметров Вы можете выполнить ./configure --help.

Детали различных параметров конфигурации рассмотрены ниже. Модуль Apache:

Для построения PHP3 в качестве модуля Apache ответьте "yes" в пункте "Build as an Apache module?" (параметр конфигурации --with-apache= DIR) и определить базовый каталог дистрибутива Apache. Если Вы распаковали свой дистрибутив Apache в директорию /usr/local/www/apache_1.2.4 то она и будет Вашей базовой директорией дистрибутива Apache. Директория по умолчанию /usr/local/etc/httpd. Модуль fhttpd:

При построении fhttpd в качестве модуля fhttpd ответьте "yes" в пункте "Build as an fhttpd module?" (параметр конфигурации --with-fhttpd=DIR) и определить базовый каталог исходных кодов fhttpd. По умолчанию это /usr/local/src/fhttpd. Если Вы запускаете fhttpd, то построение PHP3 в качестве модуля даст лучшую производительность и возможность контроля за удаленным исполнением. Версия CGI:

По умолчанию PHP3 формируется как программа CGI. Если Вы используете web server с поддержкой PHP3 в качестве модуля, то в своих решениях Вы должны исходить из производительности. Однако CGI версия дает возможность пользователям Apache исполнять страницы с поддержкой PHP под различными идентификаторами пользователя.

Параметры поддержки базы данных:

PHP имеет собственную поддержку для нескольких баз данных (так же как ODBC):

Adabas D
--with-adabas =DIR

Компиляция с поддержкой Adabas D. Параметр - установочная директория Adabas D, по умолчанию /usr/local/adabasd.

Adabas home page

dBase
--with-dbase

Включает условный атрибут поддержки Dbase. Не требует внешних библиотек.

filePro
--with-filepro

Включает условный атрибут поддержки filePro только для чтения. Не требует внешних библиотек.

mSQL
--with-msql=DIR

Включает поддержку mSQL. Параметр этой опции - установочная директория mSQL, по умолчанию /usr/local/Hughes. Это директория по умолчанию дистрибутива mSQL 2.0 configure автоматически определяет, какую версию mSQL Вы используете, а PHP3 поддерживает как версию 1.0, так и 2.0, но если Вы компилируете PHP2 с версией mSQL1.0, то можете получить доступ только к базам данных mSQL1.0 и наоборот.

mSQL home page

MySQL
--with-mysql=DIR

Включает поддержку MySQL. Параметр в этой опции - установочная директория MySQL, по умолчанию /usr/local. Она является директорией по умолчанию в дистрибутиве MySQL.

Посмотрите также директивы MySQL Configuration в configuration file.

MySQL home page

iODBC
--with-iodbc=DIR

Включает поддержку iODBC. Этот признак был разработан сначала для iODBC Driver Manager, перераспределяемого ODBC driver manager, который выполняется под множеством разновидностей UNIX. Параметром этой опции является установочная директория iODBC, по умолчанию /usr/local.

FreeODBC home page

OpenLink ODBC
--with-openlink=DIR

Включает поддержку OpenLink ODBC. Параметром этой опции является установочная директория OpenLink ODBC, по умолчанию /usr/local/openlink.

OpenLink Software's home page

Oracle
--with-oracle=DIR

Включает поддержку Oracle. Протестирован и должен работать на версиях Oracle от 7.0 до 7.3. Параметром является директория ORACLE_HOMEВы не должны определять этот параметр, если была установлена среда окружения Oracle.

Oracle home page

PostgreSQL
--with-pgsql=DIR

Включает поддержку PostgreSQL. Параметром является базовая установочная директория PostgreSQL, по умолчанию /usr/local/pgsql.

PostgreSQL home page

Solid
--with-solid=DIR

Включает поддержку Solid. Параметром является установочная директория Solid, по умолчанию /usr/local/solid.

Solid home page

Sybase
--with-sybase=DIR

Включает поддержку Sybase. Параметром является установочная директория Sybase, по умолчанию /home/sybase.

Sybase home page

Sybase-CT
--with-sybase-ct=DIR

Включает поддержку Sybase-CT. Параметром является установочная директория Sybase, по умолчанию /home/sybase.

Velocis
--with-velocis=DIR

Включает поддержку Velocis. Параметром этой опции является установочная директория OpenLink ODBC, по умолчанию /usr/local/velocis.

Velocis home page

A custom ODBC library
--with-custom-odbc=DIR

Включает поддержку для произвольной custom ODBC library. Параметром является базовая директория, по умолчанию /usr/local.

Эта опция подразумевает, что Вы определили CUSTOM_ODBC_LIBS, когда исполняется сценарий конфигурации. Вы также должны иметь правильный заголовочный файл odbc.h где-нибудь в путях включения. Если у Вас его нет, то создайте свой заголовочный файл и включите его отсюда. Он может также требовать несколько внешних определений, особенно когда это на нескольких платформах. Определите их в CFLAGS.

Например Вы можете использовать Sybase SQL Anywhere on QNX следующим образом: CFLAGS=-DODBC_QNX LDFLAGS=-lunix CUSTOM_ODBC_LIBS="-ldblib -lodbc" ./configure --with-custom-odbc=/usr/lib/sqlany50

Unified ODBC
--disable-unified-odbc

Отключает Unified ODBC модуль, который является общим интерфейсом ко всем базам данных с интерфейсом, основанным на ODBC, таких как Solid и Adabas D. Это также работает для нормальных библиотек ODBC. Был проверен с iODBC, Solid, Adabas D и Sybase SQL Anywhere. Требуется, чтобы один (и только один) из этих модулей или модуль Velocis был включен или определена пользовательская библиотека ODBC. Этот параметр применим только если используется одна из следующих опций --with-iodbc, --with-solid, --with-adabas, --with-velocis, или --with-custom-odbc

LDAP
--with-ldap=DIR

Включает поддержку LDAP (Lightweight Directory Access Protocol). Параметром является базовая установочная директория LDAP, по умолчанию /usr/local/ldap.

Более подробную информацию по LDAP можно найти в RFC1777 и RFC1778.

Другие параметры конфигурации:

--enable-sysvsem
--enable-sysvsem

Включает поддержку для семафоров Sys V (поддерживается большинством разновидностей UNIX). Для получения подробной информации смотрим Semaphore and Shared Memory documentation.

--enable-sysvshm
--enable-sysvshm

Включает поддержку разделяемой памяти для Sys V (поддерживается большинством разновидностей UNIX).

--with-xml
--with-xml

Включает поддержку для непроверенных синтаксических анализаторов XML, используя библиотеку от James Clark's expat library.

--enable-maintainer-mode
--enable-maintainer-mode

Включает дополнительные зависимости и предупреждения компилятора, используемые некоторыми разработчиками PHP3.

--with-system-regex
--with-system-regex

Использует библиотеку регулярных выражений прежде, чем собственные условия. Если Вы построили PHP3 в качестве модуля сервера, Вы должны использовать одинаковую библиотеку - и когда собираете PHP3 и когда собираете сервер. Включите эту опцию, если системные библиотеки обеспечивают специальные свойства, которые Вам требуются. Рекомендуется при возможности использовать собственные библиотеки.

--with-config-file-path
--with-config-file-path=DIR

Маршрут, используемый для просмотра the php3.ini file при старте PHP.

--with-exec-dir
--with-exec-dir=DIR

Разрешить только запуск исполнимых файлов в DIR при нахождении в защищенном режиме. По умолчанию это /usr/local/bin.Эта опция только устанавливает значение по умолчанию, которое потом можно изменить при помощи директивы safe_mode_exec_dir в configuration file.

--disable-debug
--disable-debug

Не включает информацию об отладке в библиотеке или исполнимой программе. Отладочная информация просто точно указывает на ошибки, поэтому можно выключить отладку, пока PHP3 находится в стадии бета или альфа версий.

--enable-safe-mode
--enable-safe-mode

Включает защищенный режим (safe mode) по умолчанию. Это накладывает некоторые ограничения на действия PHP, таких как открытие файлов только внутри корня документа. Для более подробной информации смотрите Security chapter. Пользователи CGI всегда должны включать безопасный режим. Эта опция только устанавливает значение по умолчанию, которое потом можно включить или выключить при помощи директивы safe_mode в configuration file.

--enable-track-vars
    --enable-track-vars

Указывает PHP3 отслеживать пришедшие переменные GET/POST/cookie в массивах HTTP_GET_VARS, HTTP_POST_VARS и HTTP_COOKIE_VARS. Эта опция только устанавливает значение по умолчанию, которое потом можно включить или выключить при помощи директивы track_vars в configuration file.

--enable-magic-quotes
--enable-magic-quotes

Включает по умолчанию системные квоты. Эта опция только устанавливает значение по умолчанию, которое потом можно включить или выключить при помощи директивы magic_quotes_runtime в configuration file.

--enable-debugger
--enable-debugger

Включает внутреннюю поддержку PHP3 debugger. Это свойство находится в стадии испытания. Смотрим также директивы Debugger Configuration в configuration file.

--enable-discard-path
--enable-discard-path

Если это включено, то бинарный PHP CGI может быть безопасно помещен вне дерева web и пользователи не смогут обойти защиту .htaccess.

--enable-bcmath
--enable-bcmath

Включает стиль bcпроизвольной точности математических функций. Смотрим также опцию bcmath.scale в configuration file.

--enable-force-cgi-redirect
--enable-force-cgi-redirect

Включает проверку безопасности для внутренних переадресаций сервера (redirect). Вы должны использовать это, если запускаете CGI версию с Apache.

Когда PHP используется в качестве исполняемого CGI, PHP по умолчанию сначала всегда проверяет, что используется переадресацией (например под Apache, используя директивы Action). Это дает уверенность, что исполняемый PHP не может использоваться для того, чтобы обойти стандартные процедуры установления прав web сервера путем непосредственного вызова, как например http://my.host/cgi-bin/php/secret/doc.html. Этот пример, доступен на http://my.host/secret/doc.html но игнорирует все установленные httpd правила безопасности для директории /secret.

Не установленная опция отключает проверку и дает возможность обхода защиты httpd и настроек предъявления полномочий. Делайте это только тогда, когда программное обеспечение Вашего сервера неспособно указать, что была выполнена безопасная переадресация и все Ваши файлы в корне документа, а также директории пользователей общедоступны.

--disable-short-tags
--disable-short-tags

Отключает краткую форму <? ?>тегов PHP3. Вы должны отключить краткую форму, если хотите использовать PHP3 c XML. При отключенной краткой форме принимается только тег PHP3 <?php ?>. Эта опция только устанавливает значение по умолчанию, которое потом можно включить или выключить при помощи директивы short_open_tag в configuration file.

--enable-url-includes
--enable-url-includes

Дает возможность выполнять код на других HTTP и FTP серверах непосредственно из PHP3 с include().

--disable-syntax-hl
--disable-syntax-hl

Выключает синтаксическое выделение.

CPPFLAGS и LDFLAGS

При сборке PHP3 установщик просматривает заголовочные и библиотечные файлы в различных директориях, измените соответственно переменные окружения CPPFLAGS и LDFLAGS. Если Вы используете нормальный shell, то вы должны написать LDFLAGS=-L/my/lib/dir CPPFLAGS=-I/my/include/dir ./configure Построение:

Когда PHP3 сконфигурирован, Вы готовы к построению исполнимых CGI или библиотеку PHP3. Об этом заботится команда make. Если Вы потерпели неудачу и не можете понять почему, то смотрите раздел Problems section.

VPATH

Проверка:

Если Вы собрали PHP3 в качестве программы CGI, Вы можете проверить результат, выполнив команду make test. Это хорошая идея - проверить результат сборки. Этим способом Вы можете обнаружить проблему с Вашим PHP3 на ранней стадии, вместо того, чтобы бороться с этим позже. Контрольное тестирование:

Если Вы собрали PHP3 в качестве программы CGI, Вы можете протестировать свою версию при помощи команды make bench. Обратите внимание, что если используется защищенный режим по умолчанию, то тест может не завершиться, если он требует больше, чем 30 секунд. Это происходит потому, что set_time_limit() не может быть использована в защищенном режиме. Используйте max_execution_time() для контроля этого времени в Ваших собственных сценариях. make bench игнорирует configuration file.

Руководство по установке PHP3 для Windows

Это руководство по установке поможет Вам установить и сконфигурировать PHP3 на Ваших web серверах под Windows 9x/NT. Данное руководство составил Bob Silva. Последнюю версию можно найти по адресу http://www.umesd.k12.or.us/php/win32install.html.

Данное руководство обеспечивает поддержку установки на:

Personal Web Server (рекомендуется новейшая версия)
Internet Information Server 3 or 4
Apache 1.3.x
Omni HTTPd 2.0b1

Изменение конфигурации для PHP3:

Все модули теперь начинаются с префикса 'php3_'. Вы должны изменить свой файл php3.ini и/или все сценарии загрузки расширений с функцией dl() (либо везде удалите префикс 'php3_'). Это предотвратит путаницу между модулями PHP и их библиотеками обеспечения.

ChangeLog, FAQ и обновленную документацию всегда можно найти на официальном сайте PHP или любом из его зеркал.

Основные шаги установки:

Данные шаги должны быть выполнены при любой установке перед специфическими инструкциями сервера:

  • Распакуйте дистрибутивный файл в директорию по Вашему выбору. Неплохим вариантом будет "C:\PHP3\".

  • Скопируйте файл 'php3-dist.ini' в Вашу директорию '%WINDOWS%' и переименуйте его в 'php3.ini'. Ваша директория '%WINDOWS%' обычно:

    c:\windows for Windows 95/98
    c:\winnt or c:\winnt40 for NT servers

  • Отредактируйте Ваш файл 'php3.ini':

    • вам потребуется изменить 'extension_dir' на путь к Вашей установочной директории PHP, либо куда Вы поместили файлы 'php3_*.dll' (например c:\php3);

    • установите 'doc_root' в путь, где располагается document_root web сервера (например c:\apache\htdocs или c:\webroot);

    • выберите, какие модули Вы желаете загружать при старте PHP. Вы можете раскомментировать линии 'extension=php3_*.dll' для загрузки соответствующих модулей. Некоторые модули требуют дополнительной установки некоторых библиотек в систему для корректной работы. В FAQ PHP можно получить больше информации о том, где получить библиотеки поддержки. Вы можете также загружать модули динамически, используя в сценарии dl("php_*.dll");

    • на PWS и IIS Вы можете установить browscap.ini в директории 'c:\windows\system\inetsrv\browscap.ini' для Windows 95/98 и 'c:\winnt\system32\inetsrv\browscap.ini' для Windows NT. Дополнительную информацию по использованию browscap в PHP можно на зеркале mirror, выберите кнопку "source", чтобы увидеть это в действии;

Windows 95/98/NT и PWS/IIS 3:

Рекомендуемый метод конфигурирования этих серверов состоит в использовании INF файлов, поставляемых с дистрибутивом (php_iis_reg.inf). Вы можете отредактировать этот файл и убедитесь, что расширения и установочная директория PHP соответствует Вашим параметрам. Или Вы можете следовать перечисленным ниже шагам, чтобы сделать это вручную.

ПРЕДУПРЕЖДЕНИЕ: Эти шаги включают в себя непосредственную работу с windows registry. Мы настоятельно рекомендуем вам сначала сделать резервную копию registry. Группа разработчиков PHP не несет ответственности, если Вы повредите Ваш registry.

  • Запустите Regedit;

  • Перейдите к: HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services
    /W3Svc/Parameters/ScriptMap    .

  • В меню редактирования выберите New->String Value.

  • Определите расширение, которое Вы хотите использовать для ваших сценариев PHP (например .php3).

  • Дважды щелкните на значении новой строки и введите путь к php.exe exe в поле данных (например c:\php3\php.exe %s %s). '%s %s' ОЧЕНЬ важны, PHP не будет работать без этого должным образом;

  • Повторите эти шаги для каждого расширения, которое Вы хотите ассоциировать со сценариями PHP;

  • Теперь перейдите к HKEY_CLASSES_ROOT;

  • В меню редактирования выберите New->Key;

  • Определите ключ к расширению, которое Вы установили в предыдущем разделе (например .php3

  • Выделите новый ключ, в правой части окна дважды щелкните "default value" и введите phpfile.

  • Повторите последний шаг для каждого расширения, которое Вы установили в предыдущей секции;

  • Теперь создайте другой New->Key под HKEY_CLASSES_ROOT и это имя phpfile.

  • Выделите новый ключ phpfile phpfile и в правой части окна, дважды щелкните "default value" и введите PHP Script.

  • Щелкните правой клавишей на phpfile и выберите New->Key, это имя Shell.

  • Щелкните правой клавишей на Shell и выберите New->Key, это имя open.

  • Щелкните правой клавишей на open и выберите New->Key, это имя command.

  • Выделите новый ключ command и в правой части окна дважды щелкните на "default value" и введите путь к php.exe. Например: c:\php3\php.exe -q %1. (не забудьте %1).

  • Выйдите из Regedit;

Пользователи PWS и IIS 3 теперь имеют полностью работающую систему. Пользователи IIS 3 могут использовать tool от Steven Genusa для конфигурирования своих карт сценариев.

Windows NT и IIS 4

Для установки PHP3 на NT Server с запущенным IIS4 следуйте следующим инструкциям:

  • В Internet Service Manager (MMC) выберите Web site или отправной каталог приложения;

  • Откройте меню свойства каталога (щелкните правой клавишей мыши и выберите свойства) и тогда щелкните Home Directory, Virtual Directory или Directory tab;

  • Щелкните кнопку Configuration и тогда выберите App Mappings tab;

  • Щелкните Add, в рамке Executable наберите c:\path-to-php-dir\php.exe %s %s. Вы ДОЛЖНЫ подставить в конце %s %s , PHP не будет функционировать правильно, если Вы этого не сделаете;

  • В рамке Extension определите расширение файла, которое Вы желаете ассоциировать со сценариями PHP (обычно (.php3 и .phtml);

  • Установите требуемую безопасность (это делается в Internet Service Manager) и, если Ваш NT Server использует файловую систему NTFS, добавьте права на исполнение для директории I_USR_, которая содержит php.exe.

Windows 9x/NT и Apache 1.3.x

Вы должны редактировать Ваш файл srm.conf или httpd.conf , чтобы сконфигурировать Apache для работы с исполняемыми PHP CGI.

Хотя может быть несколько вариантов конфигурирования PHP под Apache, это делается достаточно просто даже для новичка. Пожалуйста, обратитесь к документации по Apache для получения информации о директивах конфигурации.

  • ScriptAlias /php3/"c:/path-to-php-dir/php.exe"

  • AddType application/x-httpd-php3 .php3

  • AddType application/x-httpd-php3 .phtml

  • Action application/x-httpd-php3 "php3/php.exe"

Для обеспечения возможности использования исходного текста, просто создайте файл сценария PHP и вставьте этот код в: . Substitute original_php_script.php3php3 с именем желательного файла источника (это только один из путей). Обратите внимание, что на Win-Apache все обратные слеши в пути предложения, такого как "c:\directory\file.ext" должны быть заменены на прямые.

Omni HTTPd 2.0b1 для Windows

Данная конфигурация должно быть самая простая:

Шаг 1: Установите Omni server;
Щелкните правой клавишей на голубой иконке OmniHTTPd в system tray и выберите Properties
Шаг 3: Щелкните на Web Server Global Settings
Шаг 4: На 'External' tab введите: virtual = .php3 | actual = c:\path-to-php-dir\php.exe
Шаг 5: На Mime tab, введите: virtual = wwwserver/stdcgi | actual = .php3
Шаг 6: Щелкните OK

Повторите шаги 2 - 6 для каждого расширения, которое Вы желаете ассоциировать с PHP.

Модули PHP:

Таблица 3-1. Модули PHP
php3_calendar.dll | Функции преобразования календаря
php3_crypt.dll | Функции шифрования
php3_dbase.dll | Функции баз данных
php3_dbm.dll | Эмуляция GDBM посредством Berkely DB2 library
php3_filepro.dll | Доступ READ ONLY к базам данных filepro
php3_gd.dll | Библиотека функций GD для манипуляций с gif
php3_hyperwave.dll | Функции HyperWave
php3_imap4r2.dll | Функции IMAP 4
php3_ldap.dll | Функции LDAP
php3_msql1.dll | Клиент mSQL 1
php3_msql2.dll | Клиент mSQL 2
php3_mssql.dll | Клиент MSSQL (требует MSSQL DB-Libraries)
php3_mysql.dll | Функции MySQL
php3_nsmail.dll | Функции Netscape mail
php3_oci73.dll | Функции Oracle
php3_snmp.dll | Функции SNMP (только для NT!)
php3_zlib.dll | Функции ZLib

Глава 3. Установка. Проблемы?

Читайте FAQ:

Некоторые проблемы встречаются чаще других. Наиболее распространенные описаны в PHP3 FAQ, который можно найти по адресу: http://www.php.net/FAQ.php3

Сообщения об ошибках:

Если Вы считаете, что нашли ошибку в PHP3, то сообщите о ней. Разработчики PHP3 вероятно не знают об этом и если Вы о ней не сообщите, то она так и не будет исправлена. Формы для сообщений об ошибках доступны на сети сайтов PHP3, главная форма находится по адресу: http://ca.php.net/bugs.php3.

Другие проблемы:

Если Вы все еще не можете решить проблему, то возможно кто-нибудь из списка рассылки PHP3 способен Вам помочь. Вы прежде всего должны проверить архив на тот случай, если кто-нибудь уже ответил людям с подобными проблемами. Архив можно найти по адресу http://www.tryc.on.ca/php3.html. Для того, чтобы подписаться на список рассылки PHP3 пошлите пустое письмо по адресу php3-subscribe@lists.php.net. Адрес списка рассылки php3@lists.php.net.

Если Вы хотите получить помощь через список рассылки, пожалуйста, попробуйте быть точным и дать необходимые детали о Вашем окружении (операционная система, версия PHP, какой используется web server, запускаете Вы PHP как CGI или в качестве модуля и т.д.) и желательно было бы предоставить код, чтобы другие могли воспроизвести и протестировать Вашу проблему.

Безопасность

PHP является мощным инструментом. Как и в случае с другими мощными средствами, Вы можете навредить сами себе. PHP функционирует таким образом, что если его небрежно использовать, то могут возникнуть проблемы с безопасностью на Вашей системе. Лучший путь для предотвращения такой ситуации - всегда знать, что Вы делаете.


Глава 4. Конфигурация

Файл php3.ini

Файл php3.ini читается при запуске синтаксического анализатора PHP. Для версий серверного модуля PHP, это случается только один раз, когда запускается веб-сервер. Для версии CGI это случается на каждом вызове.

Только для каждой директивы указанной здесь, имеется соответствующая директива Apache в httpd.conf. Просто добавьте php3_ в начале имен директив, указанных здесь.

Вы можете посмотреть установочные параметры большинства значений конфигурации вызвав функцию phpinfo().

Основные директивы конфигурации
auto_append_file string

Определяет имя файла, который автоматически проверяется после основного файла. Файл включается так же, как если бы была вызвана функция include(), с использованием include_path.

Специальное значение none запрещает авто-добавление.

Примечание: Если сценарий обрывается функцией exit(), авто-добавление не произойдет.

auto_prepend_filestring

Определяет имя файла, который автоматически проверяется перед основным файлом. Файл включается так же, как если бы была вызвана функция include(), с использованием include_path.

Специальное значение none запрещает авто-добавление.

cgi_ext string
display_errors boolean

Это определяет, должны ли ошибки печататься на экране как часть HTML вывода или нет.

doc_root string

Главный каталог("root directory") PHP на сервере. Используется только когда он не пустой. Если PHP сконфигурирован при помощи safe mode, то никакие другие файлы за пределами этого каталога не обслуживаются.

engine boolean

Эта директива действительно полезна только в модуле PHP под Apache. Это используется на сайтах, где необходимо включать и выключать синтаксический анализ PHP на определенные каталоги и виртуальные серверы. Установкой php3_engine off в допустимом месте файла httpd.conf, PHP можно запрещать и разрешать.

error_log string

Имя файла, куда сохраняется журнал ошибок(log file) сценариев. Если используется специальное значение syslog, ошибки отправляются в системный журнал(system logger). В UNIX'е это syslog(3), а в Windows NT это журнал событий (event log). Системный журнал не поддерживается в Windows 95.

error_reporting integer

Устанавливает уровень сообщений об ошибках. Параметр является целым, представляющим битовую область. Добавьте те значения уровней сообщений об ошибках, которые Вы хотите.

Таблица 4-1. Уровни сообщений об ошибках
bit value | допустимые сообщения
1 | нормальные ошибки
2 | нормальные предупреждения
4 | ошибки синтаксического анализатора
8 | некритичные предупреждения стиля

Значение по умолчанию - 7 (показываются нормальные ошибки, нормальные предупреждения и синтаксические ошибки).
open_basedir string

Ограничивает файлы, которые могут открываться PHP в определенном директории-дереве.

Когда сценарий пытается открыть файл с помощью, например, fopen или gzopen, наличие/расположение файла проверяется. Когда файл находится за пределами определенного директория-дерева, PHP откажется открыть его. Все символьные ссылки определены, так что нет возможности избежать этого ограничения с помощью symlink.

Специальное значение . показывает что каталог, в котором находится сценарий, используется как основной каталог.

По умолчанию допускается открытие всех файлов.

gpc_order string

Устанавливает допустимость GET/POST/COOKIE в анализе. Установка по умолчанию этой директивы - "GPC". Установка ее в "GP", например, вынудит PHP полностью игнорировать cookies и перезапишет любые переменные метода GET переменными метода POST с одинаковыми именами.

include_path string

Определяет список каталогов где будут располагаться файлы для функций require() , include() и fopen_with_path() . Формат подобен формату системной переменной окружения PATH : список каталогов разделяется двоеточием в UNIX или точкой с запятой в Windows.

Пример 4-1. UNIX include_path

include_path=.:/home/httpd/php-lib

Пример 4-2. Windows include_path

include_path=".;c:\www\phplib"
Значением по умолчанию этой директивы является . (только текущий каталог).

isapi_ext string
log_errors boolean

Сообщает, что независимые сообщения об ошибке сценария должны регистрироваться в журнале ошибок сервера. Этот выбор таким образом является специфичным для сервера.

magic_quotes_gpc boolean

Устанавливает magic_quotes состояние для GPC (Get/Post/Cookie) операций. Когда magic_quotes включено (on), все ' (одиночные кавычки), " (двойные кавычки), \ (обратные слэши) и нулевые значения (NUL's) записываются с обратной косой чертой автоматически. Если также включено magic_quotes_sybase, одиночная кавычка записывается с дополнительной одиночной кавычкой вместо обратной косой черты.

magic_quotes_runtime boolean

Если magic_quotes_runtime разрешено, большинство функций, которые возвращают данные из любого внешнего источника разной природы, включая базы данных и текстовые файлы, будут иметь кавычки, записанные с обратной косой чертой. Если magic_quotes_sybase также включены, одиночная кавычка записывается с дополнительной одиночной кавычкой вместо обратной косой черты.

magic_quotes_sybase boolean

Если magic_quotes_sybase также разрешено, одиночная кавычка записывается с дополнительной одиночной кавычкой вместо обратной косой черты, если magic_quotes_gpc или magic_quotes_runtime разрешены.

max_execution_time integer

Эта установка определяет максимальное время в секундах допустимое для сценария, прежде чем он будет прекращен анализатором. Это помогает предохраниться от плохо/некорректно написанных сценариев.

memory_limit integer

Эта установка определяет максимальный размер памяти в байтах, допустимый для этого сценария. Это помогает запретить плохо/некорректно написанным сценариям использовать всю доступную память на сервере.

nsapi_ext string
short_open_tag boolean

Задает допустимость короткой формы ( <? ?> тегов PHP . Если вы хотите использовать PHP совместно с XML, эту опцию необходимо отключить. Если опция отключена, вы должны использовать длинную форму тегов ( <?php ?> ).

sql.safe_mode boolean
track_errors boolean

Если опция разрешена, последнее сообщение об ошибке всегда будет представлена в глобальной переменной $php_errormsg.

track_vars boolean

Если опция разрешена, входящая информация GET, POST и cookie может быть найдена в глобальных ассоциативных массивах $HTTP_GET_VARS , $HTTP_POST_VARS и $HTTP_COOKIE_VARS , соответственно.

upload_tmp_dir string

Временный каталог, используемый для хранения файлов при их загрузке на сервер. Должен допускать запись, независимо от того, каким пользователем PHP используется.

user_dir string

Основное имя каталога, используемого в домашнем каталоге пользователей для файлов PHP, например public_html .

warn_plus_overloading boolean

Если разрешено, эта опция выдает при выводе PHP сообщение когда оператор плюс( + ) используется в строке. Это должно облегчить поиск сценариев, которые должны быть перезаписаны с заменой на ( . ) - string concatenator.

Директивы Конфигурации Почты
SMTP string

Имя DNS или IP адрес сервера SMTP, который должен использоваться PHP под Windows для отправки сообщения функцией mail().

sendmail_from string

Определяет "From:" - почтовый адрес, который используется в сообщении, отправленном PHP под Windows.

sendmail_path string

Указывает где может быть найдена программа sendmail , обычно это /usr/sbin/sendmail или /usr/lib/sendmail
configure делает честную попытку определить это за вас и устанавливает значение по умолчанию, но в случае неудачи вы можете установить это здесь.

Системы не использующие sendmail должны установить оболочку/замену sendmail их предлагаемой системой почты, если имеется. Например, Qmail пользователи могут указать /var/qmail/bin/sendmail.

Директивы Конфигурации Safe Mode
safe_mode boolean

Устанавливает допустимость PHP safe mode. Читайте главу Безопасность (Security) для большей информации

safe_mode_exec_dir string

Если PHP используется в safe mode, system() и другие функции, выполняющие системные программы, отказываются запускать программы, которые находятся не в этом каталоге.

Debugger Configuration Directives
debugger.host string

DNS-имя или IP-адрес хоста используемого отладчиком.

debugger.port string

Номер порта используемого отладчиком.

debugger.enabledboolean

Задает допустимость использования отладчика.

Директивы Загрузки Расширений(Extension Loading)
enable_dl boolean

Эта директива действительно полезна только в модуле PHP под Apache. Вы можете разрешать/запрещать динамическую загрузку расширений PHP функцией dl() раздельно по каталогам и/или по виртуальным серверам.

Основная причина для выключения динамической загрузки - безопасность. С динамической загрузкой, можно игнорировать все ограничения safe_mode и open_basedir.

По умолчанию динамическая загрузка должна допускаться, за исключением случаев, когда используется safe-mode. В safe-mode всегда недопустимо использование dl() .

extension_dir string

В каком каталоге PHP должен искать динамически загружаемые расширения.

extension string

Какие динамически загружаемые расширения загрузить, при запуске PHP.

Директивы конфигурации MySQL
mysql.allow_persistentboolean

Допустить постоянные/устойчивые MySQL соединения.

mysql.max_persistent integer

Максимальное число постоянных MySQL соединений за один процесс.

mysql.max_links integer

Максимальное число MySQL соединений за процесс, включая постоянные соединения.

Директивы конфигурации mSQL

msql.allow_persistent boolean

Допустить постоянные mSQL соединения.

msql.max_persistent integer

The maximum number of persistent mSQL connections per process.

msql.max_links integer

Максимальное число постоянных mSQL соединений за один процесс.

Директивы конфигурации Postgres

pgsql.allow_persistent boolean

Допустить постоянные/устойчивые соединения Postgres.

pgsql.max_persistent integer

Максимальное число постоянных соединений Postgres за процесс.

pgsql.max_links integer

Максимальное число Postgres соединений за процесс, включая постоянные соединения.

Директивы Конфигурации Sybase

sybase.allow_persistent boolean

Допустить постоянные Sybase соединения.

sybase.max_persistent integer

Максимальное число постоянных Sybase соединений за процесс.

sybase.max_links integer

Максимальное число Sybase соединений за процесс, включая постоянные соединения.

Директивы Конфигурации Sybase-CT

sybct.allow_persistent boolean

Допустить постоянные Sybase-CT соединения. По умолчанию включено.

sybct.max_persistent integer

Максимальное число постоянных Sybase-CT соединений за процесс. По умолчанию значение -1 означающее неограниченное количество.

sybct.max_links integer

Максимальное число Sybase-CT соединений за процесс, включая постоянные соединения. По умолчанию значение -1 означающее неограниченное количество.

sybct.min_server_severity integer

Сообщения Сервера со степенью более чем или равной sybct.min_server_severity будут сообщены как предупреждения. Эта величина может также устанавливаться из сценария вызовом sybase_min_server_severity() . Значение по умолчанию - 10 , которое сообщает ошибки строгости информации, или выше.

sybct.min_client_severity integer

Сообщения библиотеки Клиента со строгостью более чем или равной sybct.min_client_severity будут сообщены как предупреждениях. Эта величина может также устанавливаться из сценария вызовом sybase_min_client_severity() . По умолчанию - 10, что эффективно запрещает вывод.

sybct.login_timeout integer

Максимальное время (в секундах) ожидания повторной попытки соединения, прежде чем будет отказ. Имейте в виду, что если max_execution_time превышен когда время попытки соединения закончится, ваш сценарий будет расторгнут прежде, чем будут предприняты какие-либо действия на случай отказа. По умолчанию - одна минута.

sybct.timeout integer

Максимальное время(в секундах)ожидания окончания select_db или выполнения запроса. Имейте в виду, что если max_execution_time превышен, когда время функционирования истекает, ваш сценарий будет расторгнут прежде, чем будут предприняты какие-либо действия на случай отказа. По умолчанию не ограничено.

sybct.hostname string

Имя хоста, с которым вы хотите соединиться, для показа sp_who. По умолчанию - none.

Директивы Конфигурации BC Math

bcmath.scale integer

Количество десятичных цифр для всех функций bcmath.

Директивы Конфигурации Возможностей Броузера

browscap string

имя файла возможностей браузера.

Директивы Конфигурации Унифицированных ODBC

uodbc.default_db string

ИСТОЧНИК ДАННЫХ ODBC, для использования, если ничего не определено в odbc_connect() или odbc_pconnect() .

uodbc.default_user string

Имя пользователя, используемое если нет определений в odbc_connect() или odbc_pconnect() .

uodbc.default_pw string

Пароль, используемый, если не определено в odbc_connect() или odbc_pconnect() .

uodbc.allow_persistent boolean

Допустить постоянные/устойчивые ODBC соединения.

uodbc.max_persistent integer

Максимальное число постоянных ODBC соединений за процесс.

uodbc.max_links integer

Максимальное число ODBC соединений за процесс, включая постоянные соединения.

Модуль Apache

Директивы конфигурации модуля Apache
Модуль CGI переадресации module/action
CGI
Виртуальные хосты

Безопасность

PHP - мощный язык и интерпретатор, независимо от того, включен ли он в веб-сервер как модуль или выполняется как разделение исполнимых файлов(binary) CGI, он может иметь доступ к файлам, выполнять команды и открывать сетевые соединения на сервере. Эти свойства дают возможность выполнять что-нибудь на веб-сервере небезопасное по умолчанию. PHP разработан специально для того чтобы быть более безопасным языком для написания программ CGI, чем Perl или C.
С правильным выбором compile-time и runtime опций конфигурации он дает вам как раз ту комбинацию свободы и безопасности, которая вам нужна.

Как есть много разных путей использования PHP, есть и большой выбор конфигураций, управляющих поведением PHP. Большой выбор опций гарантирует, что вы можете использовать PHP для многих целей, но это также означает что есть комбинации этих опций и, также, конфигураций сервера, которые заканчиваются небезопасной установкой. Эта глава объясняет различные комбинации опций конфигурации и ситуации, в которых они могут быть удачно использованы.

CGI binary

Возможные атаки

Использование PHP как исполнимых файлов CGI - выбор для установок, которые по некоторой причине не хотят внедрить PHP как модуль в программное обеспечение сервера (подобно Apache), или PHP будет использоваться с другими типами оболочек CGI, чтобы создать надежное окружение chroot и setuid для сценариев. Эта установка обычно включает установку выполняемого(binary) PHP в каталог cgi-bin на веб-сервере. Бюллетень CERT CA-96.11 рекомендует кроме того, устанавливать любые интерпретаторы в cgi-bin. Даже если исполнимый PHP может быть использован в качестве автономного интерпретатора, PHP разработан для того чтобы предохранить от атаки, которую эта установка делает возможной:

  • Доступ к системным файлам: http://my.host/cgi-bin/php?/etc/passwd

    Информация запроса в url после знака вопроса (?) проходит как аргументы командной строки интерпретатору через интерфейс CGI. Обычно переводчики открывают и выполняют файл указанный как первый аргумент в командной строке.

    Вызванный как исполняемый CGI-файл, PHP отказывается интерпретировать командные аргументы строки.

  • Доступ к любым веб-документам на сервере: http://my.host/cgi-bin/php/secret/doc.html

    Часть URL с информацией о пути, стоящая после имени PHP-файла, /secret/doc.html обычно используется, чтобы определить имя файла, который должен открываться и интерпретироваться CGI программой. Обычно некоторые директивы конфигурации веб-сервера(Apache: Action) используются, чтобы перенаправить запросы к документам подобно http://my.host/secret/script.php3 на PHP интерпретатор. С такой установкой веб-сервер сначала проверяет разрешения доступа в каталоге /secret , и потом создает запрос перенаправления http://my.host/cgi-bin/php/secret/script.php3 . К несчастью, если запрос не дается изначально в этой форме, веб-сервер не проверяет доступ к файлу /secret/script.php3 , но только для файла /cgi-bin/php . Таким образом любой пользователь, имеющий доступ к /cgi-bin/php , получает доступ к любым защищенным документам на сервере.

    В PHP, опция compile-time конфигурации --enable-force-cgi-redirect и директивы runtime-конфигурации doc_root и user_dir может использоваться для того чтобы отразить эту атаку, если дерево документов сервера имеет любые директории с ограничениями доступа. Смотрите ниже для полного объяснения других комбинаций.

Вариант 1: обслуживаются только общие(public) файлы

Если ваш сервер не имеет какой-либо информации, которая не ограничивается паролем или управлением доступом на основе ip, нет потребности в этих опциях конфигурации. Если ваш веб-сервер не позволяет вам производить перенаправление, или сервер не имеет пути, чтобы связаться с исполнимым PHP, который запрашивает благополучно перенаправленный запрос, вы можете указать опцию --disable-force-cgi-redirect для конфигурирования сценария.
Вы все еще должны убедиться, что ваши сценарии PHP не полагаются на этот или другой путь вызова сценария, ни непосредственно http://my.host/cgi-bin/php/dir/script.php3, ни переадресацией http://my.host/dir/script.php3.

Перенаправление может быть сконфигурировано, например в Apache, директивами AddHandler и Action (см. ниже).

Вариант 2: использование --enable-force-cgi-redirect

Эта compile-time опция предохраняет от вызова PHP напрямую с URL подобно http://my.host/cgi-bin/php/secretdir/script.php3. Вместо того чтобы выполнить запрос, PHP выполняет только грамматический разбор в этом способе если он выполнил правила перенаправления вебсервера.

Обычно переадресация в конфигурации Apache сделана со следующими директивами:

Action php3-script /cgi-bin/php
AddHandler php3-script .php3

Эта опция была протестирована только с веб-сервером Apache, и полагается на Apache чтобы установить не-стандартную внешнюю переменную CGI REDIRECT_STATUS для перенаправленных запросов. Если ваш сервер паутины не поддерживает какого-либо способа сообщать что запрос прямой или перенаправленный, Вы не можете использовать эту опцию и Вы должны использовать один из других путей запуска версии CGI, документированной здесь.

Вариант 3: установка doc_root или user_dir

Размещение активного содержания, такого как скрипты и модули, в каталогах документов веб-сервера иногда является небезопасной практикой. Если при некоторой ошибке конфигурации сценарии не выполняются, они отображаются как обычные HTML документы, что может закончиться утечкой интеллектуальной собственности или информации безопасности подобно паролям. Поэтому многие сисадмины предпочитают устанавливать другие каталоги для сценариев, которые будут доступны только через PHP CGI и, следовательно, всегда проинтерпретированы и не отображены как таковые.

Также, если недоступен метод перенаправления неуверенных запросов, как описано в предыдущем разделе, необходимо установить корневой каталог(doc_root) сценариев, который отличается от корневого каталога веб-документов.

Вы можете установить корневой каталог для скриптов директивой конфигурации doc_root в файле php3.ini , или вы можете установить переменную окружения PHP_DOCUMENT_ROOT. Если это установлено, CGI-версия PHP всегда будет добавлять doc_root и путь к файлу в запросах, так что вы всегда будете уверенны что за пределами этого каталога скрипты выполняться не будут (кроме user_dir //см.ниже).

Другая используемая опция - user_dir. Когда user_dir - не установлена, открытием файла управляет только doc_root. Открытие URL подобно http://my.host/~user/doc.php3 не даст результата при открытии файла из каталога пользователя, но вызывается файл ~user/doc.php3 из каталога doc_root (да,имя каталога начинается с тильды [~]).

Если user_dir установлена, например как public_php, запрос, подобный http://my.host/~user/doc.php3 откроет файл doc.php3 в каталоге public_php домашнего каталога пользователя. Если это /home/user, то выполняется /home/user/public_php/doc.php3.

user_dir задается независимо от doc_root, так что вы можете контролировать доступ к document root и user directory отдельно.

Вариант 4: PHP синтаксический анализатор вне дерева web

Очень безопасная опция должна установить синтаксический анализатор PHP где-нибудь вне дерева файлов web. В /usr/local/bin, например. Обратная сторона этой опции заключается в том что вы должны вставлять строку подобно:

#!/usr/local/bin/php

в первую строку любого документа, содержащего PHP тэги. Кроме того, вы должны сделать файлы выполнимыми. Точно так же, как Вы поступаете с любым другим сценарием CGI записанным в Perl или sh или любом другом языке, который использует #! shell-escape механизм для самозапуска.

Чтобы PHP получил возможность корректно оперировать с PATH_INFO и PATH_TRANSLATEDпри такой установке, php анализатордолжен быть скомпилирован с опцией конфигурации --enable-discard-path

Модуль Apache

Когда PHP используется как Apache модуль, не наследуются права пользователя Apache (обычно таковые - "nobody").


Руководство по РНР 3.0

Перевод Всероссийского Клуба Вебмастеров www.webclub.ru
  • Предисловие
    • Preface
    • Об этом руководстве
  • Описание языка
    • Введение в PHP3
      • Что такое PHP3?
      • Что может делать PHP3?
      • Краткая История PHP
    • Возможности PHP3
      • HTTP-аутификация средствами PHP
      • Создание GIF-файлов с помощью PHP
      • Поддержка file upload
      • Поддержка HTTP cookie
      • Поддержка баз данных
      • Регулярные выражения
      • Обработка ошибок
    • Установка
      • Установка из исходных кодов на UNIX
      • Руководство по установке PHP3 для Windows
      • Проблемы?
      • Безопасность
    • Конфигурация
      • Файл php3.ini
      • Apache
      • CGI
      • Виртуальные хосты
      • Безопасность

    Продолжение следует...


Содержание InfoNET Список использованых источников

Авторам

У вас наверное есть интересные заметки, публикации или просто дельные советы, а также информация, которой нет ни в одной книге или журнале по работе с программами и ПК. Так вот. Я, с сохранением всех ваших прав и букв, в удобной форме, предоставлю это большому кругу пользователей, у которых возможно есть еще больше вопросов или они еще появятся в процессе работы с ПК.

Статьи, размещенные на сервере будут доступны для чтения в течение 60 календарных дней (если Вам этот период кажется небольшим, пишите на какое время размещать статью), по истечении данного периода времени статья будет подключена в компилированный справочник, по тематике.

При размещении статьи у меня, Вы имеете возможность дать ссылку на сайт с использованием предоставленных баннеров на сайте.

Форма предоставления информации

Так как у многих существуют некоторые проблемы или даже отвращение к MS Word, я советую статьи для правильной передачи и последующего воспроизведения составлять в Блокноте (есть альтернативы - Патриот, Иероглиф, Bred). Кодировка исходных текстов - Windows-1251. При подкреплении текста иллюстрациями, в тексте указывать местоположение изображения (напр."Рисунок-file_1.gif"). Требования к изображению: размеры - максимально высота и ширина (300х600 пикселей), объем - не более 20Кб. Желательно готовить иллюстрации в формате GIF, но если не получится приму такие форматы: PNG, JPG, BMP, TIFF, WMF.

При ссылках на другие источники указывать полностью название и адрес в Сети, если это отдельный автор - его электронный адрес e-mail.

При комплектации статьи и всех прилагающихся к ней материалов упаковывать архиватором ZIP или RAR (самораспаковывающиеся архивы будут сразу удаляться!)

Успехов Вам, удачных статей и разработок!

ОСТАВЬТЕ ВАШ СЛЕД В ИНТЕРНЕТЕ!