src/Parser.php
public function parse($message)
    {
        // See if we have a full line in our buffer.
        if (($eol = strpos($message, "\r\n")) === false) {
            return null;
        }

        $eol += 2; // strlen("\r\n")
        $buf = (strlen($message) > $eol) ? substr($message, $eol) : '';
        $message = substr($message, 0, $eol);

        // Strip out invalid characters
        $message = preg_replace("/\\0|(?:(?<!\r)\n)|(?:\r(?!\n))/", '', $message);

        // Parse the message, or bail if the parser deems the line to be invalid.
        if (!preg_match($this->message, $message, $parsed)) {
            $parsed = array('invalid' => $message);
            if (strlen($buf)) {
                $parsed['tail'] = $buf;
            }
            return $parsed;
        }

        // Parse out the first full message and prefix if present
        $parsed['message'] = $parsed[0];
        if (isset($parsed['prefix'])) {
            $parsed['prefix'] = rtrim($parsed['prefix']);
        }

        // Parse command parameters
        $command = strtoupper($parsed['command']);
        if (isset($this->params[$command]) && !empty($parsed['params'])) {
            preg_match($this->params[$command], $parsed['params'], $params);
            $params = array_map(array($this, 'strip'), $params);

            // Parse targets if present
            if (isset($params[1]) && preg_match($this->target, $params[1], $targets)) {
                $parsed['targets'] = explode(',', $this->strip($targets[0]));
            }

            switch ($command) {
                // Handle MODE-specific parameters
                case 'MODE':
                    if (preg_match('/^' . $this->channel . '$/', $params['target'])) {
                        $params['channel'] = $params['target'];

                        /* Assign the value of $params['params'] to a named parameter if
                         * only one channel mode is being set.
                         * This functionality is DEPRECATED, and will not occur if more than one
                         * channel mode is being set. Use $params['params'] instead. */
                        if (isset($params['mode']) && strlen($params['mode']) == 2 && isset($params['params'])) {
                            switch ($params['mode']{1}) {
                                case 'l':
                                    $params['limit'] = $params['params'];
                                    break;
                                case 'b':
                                    $params['banmask'] = $params['params'];
                                    break;
                                case 'k':
                                    $params['key'] = $params['params'];
                                    break;
                                default:
                                    $params['user'] = $params['params'];
                                    break;
                            }
                        }
                    } else {
                        $params['user'] = $params['target'];
                    }
                    unset($params['target']);
                    break;
                // Handle CTCP messages
                case 'PRIVMSG':
                case 'NOTICE':
                    if ($params && preg_match($this->ctcp, end($params), $ctcp)) {
                        $parsed['ctcp'] = $this->removeIntegerKeys($ctcp);
                        if (isset($this->ctcpParams[$parsed['ctcp']['command']])
                            && !empty($parsed['ctcp']['params'])) {
                            $ctcpParams = ltrim($parsed['ctcp']['params']);
                            preg_match($this->ctcpParams[$parsed['ctcp']['command']], $ctcpParams, $ctcpParsed);
                            $parsed['ctcp']['params'] = array_merge(
                                $this->removeIntegerKeys($ctcpParsed),
                                array('all' => $ctcpParams)
                            );
                        }
                    }
                    break;
            }

            // Clean up and store the processed parameters
            $params = array_merge(array('all' => ltrim($parsed['params'])), array_filter($params, 'strlen'));
            $params = $this->removeIntegerKeys($params);
            $parsed['params'] = $params;
        } elseif (ctype_digit($command)) {
            if (isset($this->replies[$command])) {
                $parsed['code'] = $this->replies[$command];
            } else {
                $parsed['code'] = $command;
            }
            if (!empty($parsed['params'])) {
                // Slice off the target from the front of the reply
                $temp = explode(' ', ltrim($parsed['params']), 2);
                $parsed['target'] = array_shift($temp);
                if ($parsed['params'] = (!empty($temp)) ? (' ' . array_shift($temp)) : '') {
                    $all = ltrim($parsed['params']);
                    if (strpos($parsed['params'], ' :') !== false) {
                        list($head, $tail) = explode(' :', $parsed['params'], 2);
                    } else {
                        $head = $parsed['params'];
                        $tail = '';
                    }
                    $params = explode(' ', $head);
                    $params[] = $tail;
                    if ($params = array_filter($params, 'strlen')) {
                        $parsed['params'] = array_combine(range(1, count($params)), $params);
                        if (strlen($tail)) {
                            $parsed['params']['iterable'] = array_slice($params, 0, -1);
                            $parsed['params']['tail'] = $tail;
                        } else {
                            $parsed['params']['iterable'] = array_values($params);
                        }
                        $parsed['params']['all'] = $all;
                    }
                }
            }
        }

        // Store the remainder of the original data stream
        $parsed['tail'] = $buf;

        // Clean up and return the response
        $parsed = $this->removeIntegerKeys($parsed);
        $parsed = array_filter($parsed);
        return $parsed;
    }
public function parse($message)
    {
        // See if we have a full line in our buffer.
        if (($eol = strpos($message, "\r\n")) === false) {
            return null;
        }

        $eol += 2; // strlen("\r\n")
        $buf = (strlen($message) > $eol) ? substr($message, $eol) : '';
        $message = substr($message, 0, $eol);

        // Strip out invalid characters
        $message = preg_replace("/\\0|(?:(?<!\r)\n)|(?:\r(?!\n))/", '', $message);

        // Parse the message, or bail if the parser deems the line to be invalid.
        if (!preg_match($this->message, $message, $parsed)) {
            $parsed = array('invalid' => $message);
            if (strlen($buf)) {
                $parsed['tail'] = $buf;
            }
            return $parsed;
        }

        // Parse out the first full message and prefix if present
        $parsed['message'] = $parsed[0];
        if (isset($parsed['prefix'])) {
            $parsed['prefix'] = rtrim($parsed['prefix']);
        }

        // Parse command parameters
        $command = strtoupper($parsed['command']);
        if (isset($this->params[$command]) && !empty($parsed['params'])) {
            preg_match($this->params[$command], $parsed['params'], $params);
            $params = array_map(array($this, 'strip'), $params);

            // Parse targets if present
            if (isset($params[1]) && preg_match($this->target, $params[1], $targets)) {
                $parsed['targets'] = explode(',', $this->strip($targets[0]));
            }

            switch ($command) {
                // Handle MODE-specific parameters
                case 'MODE':
                    if (preg_match('/^' . $this->channel . '$/', $params['target'])) {
                        $params['channel'] = $params['target'];

                        /* Assign the value of $params['params'] to a named parameter if
                         * only one channel mode is being set.
                         * This functionality is DEPRECATED, and will not occur if more than one
                         * channel mode is being set. Use $params['params'] instead. */
                        if (isset($params['mode']) && strlen($params['mode']) == 2 && isset($params['params'])) {
                            switch ($params['mode']{1}) {
                                case 'l':
                                    $params['limit'] = $params['params'];
                                    break;
                                case 'b':
                                    $params['banmask'] = $params['params'];
                                    break;
                                case 'k':
                                    $params['key'] = $params['params'];
                                    break;
                                default:
                                    $params['user'] = $params['params'];
                                    break;
                            }
                        }
                    } else {
                        $params['user'] = $params['target'];
                    }
                    unset($params['target']);
                    break;
                // Handle CTCP messages
                case 'PRIVMSG':
                case 'NOTICE':
                    if ($params && preg_match($this->ctcp, end($params), $ctcp)) {
                        $parsed['ctcp'] = $this->removeIntegerKeys($ctcp);
                        if (isset($this->ctcpParams[$parsed['ctcp']['command']])
                            && !empty($parsed['ctcp']['params'])) {
                            $ctcpParams = ltrim($parsed['ctcp']['params']);
                            preg_match($this->ctcpParams[$parsed['ctcp']['command']], $ctcpParams, $ctcpParsed);
                            $parsed['ctcp']['params'] = array_merge(
                                $this->removeIntegerKeys($ctcpParsed),
                                array('all' => $ctcpParams)
                            );
                        }
                    }
                    break;
            }

            // Clean up and store the processed parameters
            $params = array_merge(array('all' => ltrim($parsed['params'])), array_filter($params, 'strlen'));
            $params = $this->removeIntegerKeys($params);
            $parsed['params'] = $params;
        } elseif (ctype_digit($command)) {
            if (isset($this->replies[$command])) {
                $parsed['code'] = $this->replies[$command];
            } else {
                $parsed['code'] = $command;
            }
            if (!empty($parsed['params'])) {
                // Slice off the target from the front of the reply
                $temp = explode(' ', ltrim($parsed['params']), 2);
                $parsed['target'] = array_shift($temp);
                if ($parsed['params'] = (!empty($temp)) ? (' ' . array_shift($temp)) : '') {
                    $all = ltrim($parsed['params']);
                    if (strpos($parsed['params'], ' :') !== false) {
                        list($head, $tail) = explode(' :', $parsed['params'], 2);
                    } else {
                        $head = $parsed['params'];
                        $tail = '';
                    }
                    $params = explode(' ', $head);
                    $params[] = $tail;
                    if ($params = array_filter($params, 'strlen')) {
                        $parsed['params'] = array_combine(range(1, count($params)), $params);
                        if (strlen($tail)) {
                            $parsed['params']['iterable'] = array_slice($params, 0, -1);
                            $parsed['params']['tail'] = $tail;
                        } else {
                            $parsed['params']['iterable'] = array_values($params);
                        }
                        $parsed['params']['all'] = $all;
                    }
                }
            }
        }

        // Store the remainder of the original data stream
        $parsed['tail'] = $buf;

        // Clean up and return the response
        $parsed = $this->removeIntegerKeys($parsed);
        $parsed = array_filter($parsed);
        return $parsed;
    }
Implements ParserInterface::parse().

@param string $message Data stream containing the message to parse
@return array|null Associative array containing parsed data if the
message is successfully parsed, null otherwise
@see \Phergie\Irc\ParserInterface::parse()