5

After upgrading to php 5.6.4 my widgets file causes:

Parse error: syntax error, unexpected 'class' (T_CLASS) in /home/path/fss-widgets.php on line 1

I'm mystified - several hours research has yielded nothing. The problem doesn't appear to be quoting, escaping, or anything else you would expect in this situation and the code looks ok to me.

<?php

/*
Plugin Name: FSS Vacancy Widget
Plugin URI: http://www.url.com/
Description: Shows recent vacancies
Author: Name
Version: 1.0
Author URI: http://www.url.com/
*/

class FSSVacancyWidget extends WP_Widget
{
  function FSSVacancyWidget()
  {
    $widget_ops = array('classname' => 'FSSVacancyWidget', 'description' => 'Displays Recent FSS Jobs on the homepage and all other pages' );
    $this->WP_Widget('FSSVacancyWidget', 'FSS Vacancies', $widget_ops);
  }

  function form($instance)
  {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
    $fss_numposts = $instance['fss_numposts'];
    $fss_vacurl = $instance['fss_vacurl'];
    $fss_morevac = $instance['fss_morevac'];
?>
    <p><label for="<?php echo $this->get_field_id('title'); ?>">Title: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label></p>
    <p><label for="<?php echo $this->get_field_id('fss_numposts'); ?>">Number of Posts (Default is 10): <input class="widefat" id="<?php echo $this->get_field_id('fss_numposts'); ?>" name="<?php echo $this->get_field_name('fss_numposts'); ?>" type="text" value="<?php echo attribute_escape($fss_numposts); ?>" /></label></p>
    <p><label for="<?php echo $this->get_field_id('fss_vacurl'); ?>">Vacancy URL: <input class="widefat" id="<?php echo $this->get_field_id('fss_vacurl'); ?>" name="<?php echo $this->get_field_name('fss_vacurl'); ?>" type="text" value="<?php echo attribute_escape($fss_vacurl); ?>" /></label></p>    
    <p><label for="<?php echo $this->get_field_id('fss_morevac'); ?>">More Vacancies Title: <input class="widefat" id="<?php echo $this->get_field_id('fss_morevac'); ?>" name="<?php echo $this->get_field_name('fss_morevac'); ?>" type="text" value="<?php echo attribute_escape($fss_morevac); ?>" /></label></p>   

<?php
  }

  function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    $instance['fss_numposts'] = $new_instance['fss_numposts'];
    $instance['fss_vacurl'] = $new_instance['fss_vacurl'];
    $instance['fss_morevac'] = $new_instance['fss_morevac'];
    return $instance;
  }

  function widget($args, $instance)
  {
    extract($args, EXTR_SKIP);

    /* User-selected settings. */
   $fss_numposts = $instance['fss_numposts'];
   $fss_vacurl = $instance['fss_vacurl'];
   $fss_morevac = $instance['fss_morevac'];

    echo $before_widget;
    $title = empty($instance['title']) ? ' ' : apply_filters('widget_title', $instance['title']);

    if (!empty($title))
      echo $before_title . $title . $after_title;;

    echo "<ul class='items'>";

    query_posts( array( 'showposts' => $fss_numposts ) );
    if ( have_posts() ) : while ( have_posts() ) : the_post();
    echo "<li><a href='".get_permalink()."'><span class='job-title'>".get_the_title()."</span><span class='job-date'>".get_the_date('d m Y')."</span></a></li>";

    endwhile; endif; wp_reset_query();

    echo "</ul>";
    echo"<a href='".$fss_vacurl."' class='view'>".$fss_morevac."</a>";

    echo $after_widget;
  }

}
add_action( 'widgets_init', create_function('', 'return register_widget("FSSVacancyWidget");') );
0
8

An error about something on line 1 that is actually on a later position means that PHP doesn't recognize your line endings.

There are three ways to encode a line ending, and PHP understands only two of them:

  1. LF, or \n, Line Feed, U+000A
  2. CR, or \r, Carriage Return, U+000D
  3. CRLF, or \r\n, the combination of the first and the second

LF is the default on systems like UNIX, Linux, and Mac OS X (since 2001).
CRLF is the default in Windows, inherited from CP/M. Just LF works on Windows too nowadays, there is no need to use CRLF anymore.
CR was the default in Classic Mac OS until 2001.

PHP doesn't understand 2., CR only, which is understandable, because no one is using that anymore. Well, almost no one. There are still some editors out there that not only allow that obsolete line ending encoding, they don't even warn their users when they are using it.

Set your editor to use LF only, and you are safe. Unfortunately, the WordPress Coding Standards are silent about this.

1
  • 1
    Somehow the file was using Mac OS 2009 line breaks - I have no idea how! Relevant XKCD xkcd.com/927 Jan 15 '17 at 13:17
2

@tosho's answer is too good.

What just happened is PHP parsers tries to parse that file and creates tokens first, and gets confused with the first token class, becuase the parser for that version of PHP cannot work well with \r characters.

Happens that also other invisible Unicode characters may break the parser. The main thing you just cannot understand the problem from the editor unless you open Hex editor.

BOM character also (props @MarkKaplun) can make problems. There are some Unicode n-dash characters that may look just like - (minus), and you can scratch your head for days.

In this case, as you confirmed \r carriage return character was your problem.

But this is dependent on PHP version. I tested your code on PHP 7 and no problem found.

I noticed that WPSO editor will trim the \r character, and I added it manually when tested.

enter image description here enter image description here

The moral of the story.

Fix the line endings from your editor, for your project via regex replace.

But also fix endings for non-PHP files.

define('CR', "\r");          // Carriage Return: Classic Mac
define('CRLF', "\r\n");      // Carriage Return and Line Feed: Windows
define('LF', "\n");          // Best: Unix, Linux, Mac, Windows


function fix_endings($s) {
    // Convert all line-endings to the Best format.
    $s = str_replace( CRLF, LF, $s );
    $s = str_replace( CR, LF, $s );
    // Don't allow out-of-control blank lines
    $s = preg_replace( "/\n{2,}/", LF . LF, $s );
    return $s;
}

The line endings are very important and may also have security implications. If the PHP parser fails on some characters you may guess some PHP functions that read files may also.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.