Source for file Client.php
Documentation is available at Client.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
* +-----------------------------------------------------------------------+
* | http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 |
* | This work (and included software, documentation such as READMEs, |
* | or other related items) is being provided by the copyright holders |
* | under the following license. By obtaining, using and/or copying |
* | this work, you (the licensee) agree that you have read, understood, |
* | and will comply with the following terms and conditions. |
* | Permission to copy, modify, and distribute this software and its |
* | documentation, with or without modification, for any purpose and |
* | without fee or royalty is hereby granted, provided that you include |
* | the following on ALL copies of the software and documentation or |
* | portions thereof, including modifications: |
* | 1. The full text of this NOTICE in a location viewable to users |
* | of the redistributed or derivative work. |
* | 2. Any pre-existing intellectual property disclaimers, notices, |
* | or terms and conditions. If none exist, the W3C Software Short |
* | Notice should be included (hypertext is preferred, text is |
* | permitted) within the body of any redistributed or derivative |
* | 3. Notice of any changes or modifications to the files, including |
* | the date changes were made. (We recommend you provide URIs to |
* | the location from which the code is derived.) |
* | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT |
* | HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, |
* | INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR |
* | FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE |
* | OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, |
* | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. |
* | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, |
* | SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE |
* | SOFTWARE OR DOCUMENTATION. |
* | The name and trademarks of copyright holders may NOT be used in |
* | advertising or publicity pertaining to the software without |
* | specific, written prior permission. Title to copyright in this |
* | software and any associated documentation will at all times |
* | remain with copyright holders. |
* +-----------------------------------------------------------------------+
* @author Heino H. Gehlsen <heino@gehlsen.dk>
* @copyright 2002-2011 Heino H. Gehlsen <heino@gehlsen.dk>. All Rights Reserved.
* @version SVN: $Id: Client.php 317347 2011-09-26 20:26:12Z janpascal $
* @link http://pear.php.net/package/Net_NNTP
require_once 'Net/NNTP/Protocol/Client.php';
* Implementation of the client side of NNTP (Network News Transfer Protocol)
* The Net_NNTP_Client class is a frontend class to the Net_NNTP_Protocol_Client class.
* @version package: 1.5.0 (stable)
* @version api: 0.9.0 (alpha)
* @see Net_NNTP_Protocol_Client
* Information summary about the currently selected group.
var $_selectedGroupSummary = null;
var $_overviewFormatCache = null;
* {@example docs/examples/phpdoc/constructor.php}
parent ::Net_NNTP_Protocol_Client ();
* {@example docs/examples/phpdoc/connect.php}
* @param string $host (optional) The hostname og IP-address of the NNTP-server to connect to, defaults to localhost.
* @param mixed $encryption (optional) false|'tls'|'ssl', defaults to false.
* @param int $port (optional) The port number to connect to, defaults to 119 or 563 dependng on $encryption.
* @param int $timeout (optional)
* - (bool) True when posting allowed, otherwise false
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::disconnect()
* @see Net_NNTP_Client::authenticate()
function connect($host = null , $encryption = null , $port = null , $timeout = null )
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: connect() !', E_USER_NOTICE );
return parent ::connect ($host, $encryption, $port, $timeout);
* Disconnect from server.
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::connect()
return parent ::disconnect ();
* Deprecated alias for disconnect().
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/authenticate.php}
* @param string $user The username
* @param string $pass The password
* - (bool) True on successful authentification, otherwise false
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::connect()
return $this->throwError ('No username supplied', null );
return $this->cmdAuthinfo ($user, $pass);
* Moves the servers 'currently selected group' pointer to the group
* a new group, and returns summary information about it.
* <b>Non-standard!</b><br>
* When using the second parameter,
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/selectGroup.php}
* @param string $group Name of the group to select
* @param mixed $articles (optional) experimental! When true the article numbers is returned in 'articles'
* - (array) Summary about the selected group
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getGroups()
* @see Net_NNTP_Client::group()
* @see Net_NNTP_Client::first()
* @see Net_NNTP_Client::last()
* @see Net_NNTP_Client::count()
// Select group (even if $articles is set, since many servers does not select groups when the listgroup command is run)
$summary = $this->cmdGroup ($group);
if (PEAR ::isError ($summary)) {
// Store group info in the object
$this->_selectedGroupSummary = $summary;
if ($articles !== false ) {
$summary2 = $this->cmdListgroup ($group, ($articles === true ? null : $articles));
if (PEAR ::isError ($summary2)) {
// Make sure the summary array is correct...
if ($summary2['group'] == $group) {
// ... even if server does not include summary in status reponce.
$summary['articles'] = $summary2['articles'];
// {{{ selectPreviousArticle()
* Select the previous article.
* Select the previous article in current group.
* {@example docs/examples/phpdoc/selectPreviousArticle.php}
* @param int $_ret (optional) Experimental
* - (integer) Article number, if $ret=0 (default)
* - (string) Message-id, if $ret=1
* - (array) Both article number and message-id, if $ret=-1
* - (bool) False if no prevoius article exists
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::selectArticle()
* @see Net_NNTP_Client::selectNextArticle()
$response = $this->cmdLast ();
if (PEAR ::isError ($response)) {
return array ('Number' => (int) $response[0 ], 'Message-ID' => (string) $response[1 ]);
return (int) $response[0 ];
return (string) $response[1 ];
// {{{ selectNextArticle()
* Select the next article.
* Select the next article in current group.
* {@example docs/examples/phpdoc/selectNextArticle.php}
* @param int $_ret (optional) Experimental
* - (integer) Article number, if $ret=0 (default)
* - (string) Message-id, if $ret=1
* - (array) Both article number and message-id, if $ret=-1
* - (bool) False if no further articles exist
* - (object) Pear_Error on unexpected failure
* @see Net_NNTP_Client::selectArticle()
* @see Net_NNTP_Client::selectPreviousArticle()
$response = $this->cmdNext ();
if (PEAR ::isError ($response)) {
return array ('Number' => (int) $response[0 ], 'Message-ID' => (string) $response[1 ]);
return (int) $response[0 ];
return (string) $response[1 ];
* Selects an article by article message-number.
* {@example docs/examples/phpdoc/selectArticle.php}
* @param mixed $article The message-number (on the server) of
* the article to select as current article.
* @param int $_ret (optional) Experimental
* - (integer) Article number
* - (bool) False if article doesn't exists
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::selectNextArticle()
* @see Net_NNTP_Client::selectPreviousArticle()
$response = $this->cmdStat ($article);
if (PEAR ::isError ($response)) {
return array ('Number' => (int) $response[0 ], 'Message-ID' => (string) $response[1 ]);
return (int) $response[0 ];
return (string) $response[1 ];
* Fetch article into transfer object.
* Select an article based on the arguments, and return the entire
* {@example docs/examples/phpdoc/getArticle.php}
* @param mixed $article (optional) Either the message-id or the
* message-number on the server of the
* @param bool $implode (optional) When true the result array
* is imploded to a string, defaults to
* - (array) Complete article (when $implode is false)
* - (string) Complete article (when $implode is true)
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getHeader()
* @see Net_NNTP_Client::getBody()
function getArticle($article = null , $implode = false )
trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE );
return $this->throwError (" Class '$class' does not exist!" );
$data = $this->cmdArticle ($article);
if (PEAR ::isError ($data)) {
return $obj = new $class($data);
* Select an article based on the arguments, and return the article
* {@example docs/examples/phpdoc/getHeader.php}
* @param mixed $article (optional) Either message-id or message
* number of the article to fetch.
* @param bool $implode (optional) When true the result array
* is imploded to a string, defaults to
* - (bool) False if article does not exist
* - (array) Header fields (when $implode is false)
* - (string) Header fields (when $implode is true)
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getArticle()
* @see Net_NNTP_Client::getBody()
function getHeader($article = null , $implode = false )
trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE );
return $this->throwError (" Class '$class' does not exist!" );
$data = $this->cmdHead ($article);
if (PEAR ::isError ($data)) {
return $obj = new $class($data);
* Select an article based on the arguments, and return the article
* {@example docs/examples/phpdoc/getBody.php}
* @param mixed $article (optional) Either the message-id or the
* message-number on the server of the
* @param bool $implode (optional) When true the result array
* is imploded to a string, defaults to
* - (array) Message body (when $implode is false)
* - (string) Message body (when $implode is true)
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getHeader()
* @see Net_NNTP_Client::getArticle()
function getBody($article = null , $implode = false )
trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getHeader() !', E_USER_NOTICE );
return $this->throwError (" Class '$class' does not exist!" );
$data = $this->cmdBody ($article);
if (PEAR ::isError ($data)) {
return $obj = new $class($data);
* Post a raw article to a number of groups.
* {@example docs/examples/phpdoc/post.php}
* @param mixed $article <br>
* - (string) Complete article in a ready to send format (lines terminated by LFCR etc.)
* - (array) First key is the article header, second key is article body - any further keys are ignored !!!
* - (mixed) Something 'callable' (which must return otherwise acceptable data as replacement)
* - (string) Server response
* - (object) Pear_Error on failure
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: post() !', E_USER_NOTICE );
return $this->mail($groups, $subject, $body, " From: $from\r\n" . $additional);
// Only accept $article if array or string
return $this->throwError ('Ups', null , 0 );
// Check if server will receive an article
$post = $this->cmdPost ();
if (PEAR ::isError ($post)) {
// Get article data from callback function
// Actually send the article
return $this->cmdPost2 ($article);
* Post an article to a number of groups - using same parameters as PHP's mail() function.
* Among the aditional headers you might think of adding could be:
* "From: <author-email-address>", which should contain the e-mail address
* of the author of the article.
* Or "Organization: <org>" which contain the name of the organization
* the post originates from.
* Or "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-address
* of the author of the post, so the message can be traced back to him.
* {@example docs/examples/phpdoc/mail.php}
* @param string $groups The groups to post to.
* @param string $subject The subject of the article.
* @param string $body The body of the article.
* @param string $additional (optional) Additional header fields to send.
* - (string) Server response
* - (object) Pear_Error on failure
function mail($groups, $subject, $body, $additional = null )
// Check if server will receive an article
$post = $this->cmdPost ();
if (PEAR ::isError ($post)) {
$header = " Newsgroups: $groups\r\n";
$header .= " Subject: $subject\r\n";
$header .= "X-poster: PEAR::Net_NNTP v1.5.0 (stable)\r\n";
if ($additional !== null ) {
// Actually send the article
return $this->cmdPost2 (array ($header, $body));
* Get the server's internal date
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getDate.php}
* @param int $format (optional) Determines the format of returned date:
* - 1: return integer/timestamp
* - 2: return an array('y'=>year, 'm'=>month,'d'=>day)
* - (object) Pear_Error on failure
$date = $this->cmdDate ();
if (PEAR ::isError ($date)) {
return array ('y' => substr($date, 0 , 4 ),
* Get new groups since a date.
* Returns a list of groups created on the server since the specified date
* {@example docs/examples/phpdoc/getNewGroups.php}
* @param mixed $time <br>
* - (integer) A timestamp
* - (string) Somthing parseable by strtotime() like '-1 week'
* @param string $distributions (optional)
* - (object) Pear_Error on failure
return $this->throwError ('$time could not be converted into a timestamp!', null , 0 );
trigger_error('$time must be either a string or an integer/timestamp!', E_USER_ERROR );
return $this->cmdNewgroups ($time, $distributions);
* Get new articles since a date.
* Returns a list of message-ids of new articles (since the specified date
* and time) in the groups whose names match the wildmat
* {@example docs/examples/phpdoc/getNewArticles.php}
* @param mixed $time <br>
* - (integer) A timestamp
* - (string) Somthing parseable by strtotime() like '-1 week'
* @param string $groups (optional)
* @param string $distributions (optional)
* - (object) Pear_Error on failure
if ($time === false || ($time === -1 && version_compare(php_version (), '5.1.0', '<'))) {
return $this->throwError ('$time could not be converted into a timestamp!', null , 0 );
trigger_error('$time must be either a string or an integer/timestamp!', E_USER_ERROR );
return $this->cmdNewnews ($time, $groups, $distribution);
* Returns a list of valid groups (that the client is permitted to select)
* and associated information.
* {@example docs/examples/phpdoc/getGroups.php}
* - (array) Nested array with information about every valid group
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getDescriptions()
* @see Net_NNTP_Client::selectGroup()
$groups = $this->cmdListActive ($wildmat);
if (PEAR ::isError ($groups)) {
switch ($groups->getCode ()) {
return $this->throwError ("The server does not support the 'LIST ACTIVE' command, and the 'LIST' command does not support the wildmat parameter!", null , null );
$groups2 = $this->cmdList ();
if (PEAR ::isError ($groups2)) {
if (PEAR ::isError ($groups)) {
* Fetch all known group descriptions.
* Fetches a list of known group descriptions - including groups which
* the client is not permitted to select.
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getDescriptions.php}
* @param mixed $wildmat (optional)
* - (array) Associated array with descriptions of known groups
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getGroups()
// Get group descriptions
$descriptions = $this->cmdListNewsgroups ($wildmat);
if (PEAR ::isError ($descriptions)) {
// TODO: add xgtitle as backup
* Fetch an overview of article(s) in the currently selected group.
* Returns the contents of all the fields in the database for a number
* of articles specified by either article-numnber range, a message-id,
* or nothing (indicating currently selected article).
* The first 8 fields per article is always as follows:
* - 'Number' - '0' or the article number of the currently selected group.
* - 'Subject' - header content.
* - 'From' - header content.
* - 'Date' - header content.
* - 'Message-ID' - header content.
* - 'References' - header content.
* - ':bytes' - metadata item.
* - ':lines' - metadata item.
* The server may send more fields form it's database...
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getOverview.php}
* @param mixed $range (optional)
* - '<message number>-<message number>'
* @param boolean $_names (optional) experimental parameter! Use field names as array kays
* @param boolean $_forceNames (optional) experimental parameter!
* - (array) Nested array of article overview data
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getHeaderField()
* @see Net_NNTP_Client::getOverviewFormat()
function getOverview($range = null , $_names = true , $_forceNames = true )
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getOverview() !', E_USER_NOTICE );
// Fetch overview via API v1.3
if (PEAR ::isError ($overview)) {
// Create and return API v1.0 compliant array
foreach ($overview as $article) {
// Rename 'Number' field into 'number'
// Use 'Message-ID' field as key
$articles[$article['Message-ID']] = $article;
// Fetch overview from server
$overview = $this->cmdXOver ($range);
if (PEAR ::isError ($overview)) {
// Use field names from overview format as keys?
if (is_null($this->_overviewFormatCache)) {
if (PEAR ::isError ($format)){
// Prepend 'Number' field
$format = array_merge(array ('Number' => false ), $format);
$this->_overviewFormatCache = $format;
$format = $this->_overviewFormatCache;
// Loop through all articles
foreach ($overview as $key => $article) {
// Loop through forld names in format
foreach ($f as $tag => $full) {
$f[$tag] = $article[$i++ ];
// If prefixed by field name, remove it
if (count($overview) == 0 ) {
// Expect multiple articles
// {{{ getOverviewFormat()
* Fetch names of fields in overview database
* Returns a description of the fields in the database for which it is consistent.
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getOveriewFormat.php}
* - (array) Overview field names
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getOverview()
$format = $this->cmdListOverviewFmt ();
if (PEAR ::isError ($format)) {
// Force name of first seven fields
':lines' => false ), $format);
* Fetch content of a header field from message(s).
* Retreives the content of specific header field from a number of messages.
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getHeaderField.php}
* @param string $field The name of the header field to retreive
* @param mixed $range (optional)
* '<message number>-<message number>'
* - (array) Nested array of
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getOverview()
* @see Net_NNTP_Client::getReferences()
$fields = $this->cmdXHdr ($field, $range);
if (PEAR ::isError ($fields)) {
if (count($fields) == 0 ) {
// Expect multiple articles
// {{{ getGroupArticles()
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getGroupArticles.php}
* @param mixed $range (optional) Experimental!
* - (object) Pear_Error on failure
$summary = $this->cmdListgroup ();
if (PEAR ::isError ($summary)) {
// Update summary cache if group was also 'selected'
if ($summary['group'] !== null ) {
$this->_selectedGroupSummary ($summary);
return $summary['articles'];
* Fetch reference header field of message(s).
* Retrieves the content of the references header field of messages via
* either the XHDR ord the XROVER command.
* Identical to getHeaderField('References').
* <b>Non-standard!</b><br>
* This method uses non-standard commands, which is not part
* of the original RFC977, but has been formalized in RFC2890.
* {@example docs/examples/phpdoc/getReferences.php}
* @param mixed $range (optional)
* '<message number>-<message number>'
* - (array) Nested array of references
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::getHeaderField()
$references = $this->cmdXHdr ('References', $range);
if (PEAR ::isError ($references)) {
switch ($references->getCode ()) {
if (true && (is_array($references) && count($references) == 0 )) {
$references2 = $this->cmdXROver ($range);
if (PEAR ::isError ($references2)) {
$references = $references2;
if (PEAR ::isError ($references)) {
foreach ($references as $key => $val) {
$references[$key] = preg_split("/ +/", trim($val), -1 , PREG_SPLIT_NO_EMPTY );
if (count($references) == 0 ) {
return reset($references);
// Expect multiple articles
* Number of articles in currently selected group
* {@example docs/examples/phpdoc/count.php}
* - (string) the number of article in group
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::group()
* @see Net_NNTP_Client::first()
* @see Net_NNTP_Client::last()
* @see Net_NNTP_Client::selectGroup()
return $this->_selectedGroupSummary['count'];
* Maximum article number in currently selected group
* {@example docs/examples/phpdoc/last.php}
* - (string) the last article's number
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::first()
* @see Net_NNTP_Client::group()
* @see Net_NNTP_Client::count()
* @see Net_NNTP_Client::selectGroup()
return $this->_selectedGroupSummary['last'];
* Minimum article number in currently selected group
* {@example docs/examples/phpdoc/first.php}
* - (string) the first article's number
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::last()
* @see Net_NNTP_Client::group()
* @see Net_NNTP_Client::count()
* @see Net_NNTP_Client::selectGroup()
return $this->_selectedGroupSummary['first'];
* Currently selected group
* {@example docs/examples/phpdoc/group.php}
* - (object) Pear_Error on failure
* @see Net_NNTP_Client::first()
* @see Net_NNTP_Client::last()
* @see Net_NNTP_Client::count()
* @see Net_NNTP_Client::selectGroup()
return $this->_selectedGroupSummary['group'];
* Test whether a connection is currently open or closed.
* @return bool True if connected, otherwise false
* @see Net_NNTP_Client::connect()
* @see Net_NNTP_Client::quit()
* @deprecated since v1.3.0 due to use of protected method: Net_NNTP_Protocol_Client::isConnected()
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: isConnected() !', E_USER_NOTICE );
return parent ::_isConnected ();
* Deprecated alias for getArticle()
function getArticleRaw ($article, $implode = false )
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getArticleRaw() !', E_USER_NOTICE );
* Deprecated alias for getHeader()
function getHeaderRaw ($article = null , $implode = false )
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getHeaderRaw() !', E_USER_NOTICE );
* Deprecated alias for getBody()
function getBodyRaw ($article = null , $implode = false )
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getBodyRaw() !', E_USER_NOTICE );
return $this->getBody($article, $implode);
* Deprecated alias for getNewArticles()
function getNewNews ($time, $groups = '*', $distribution = null )
trigger_error('You are using deprecated API v1.1 in Net_NNTP_Client: getNewNews() !', E_USER_NOTICE );
// {{{ getReferencesOverview()
* Deprecated alias for getReferences()
function getReferencesOverview ($first, $last)
trigger_error('You are using deprecated API v1.0 in Net_NNTP_Client: getReferencesOverview() !', E_USER_NOTICE );
* c-hanging-comment-ender-p: nil
Documentation generated on Mon, 11 Mar 2019 15:53:46 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|