Support » Plugin: Speed Contact Bar » ob_get_clean() creates conflict

  • Resolved Nextendweb

    (@nextendweb)


    Hi Martin (@hinjiriyo),
    I just found a bug in PHP’s ob_get_clean() function. It does not call the output buffer callbacks and it can create conflict with other plugins.

    Instead
    $content = ob_get_clean();

    You should use:

    $content = ob_get_contents();
    ob_clean();

    It does the same job, but this implementation calls the ob_start callback properly.

    See the bug report at PHP: https://bugs.php.net/bug.php?id=76563

    More details how I found this bug:
    We are testing Smart Slider 3 with several plugins. When Speed Contact Bar and Reviews (https://wordpress.org/plugins/ultimate-reviews/) is activated, Speed contact bar is not able to call ob_start() as the Reviews plugin skips that action. So Speed Contact bar was not able to open the output buffer, but at the end it closes one, and it closes Smart Slider’s output buffer which has a callback and that callback get skipped.

Viewing 9 replies - 1 through 9 (of 9 total)
  • I worked on this case few hours to come up with a new idea.

    Store the level of the output after you opened:

    private $ob_level = -1;
    
    /**
     * Activate output buffer
     *
     * @since    1.0
     */
    public function activate_buffer() {
    	// activate output buffer
    	ob_start();
    
    	$this->ob_level = ob_get_level();
    }

    Get the contents of the buffer.
    Then clean the buffer, which means you will have an empty buffer.

    public function include_contact_bar() {
    	if ( $this->is_login_page() or is_admin() ) {
    		return;
    	}
    	// correct link target for some links if desired
    	if ( isset( $this->stored_settings[ 'open_new_window_social_only' ] ) and 1 == $this->stored_settings[ 'open_new_window_social_only' ] ) {
    		$contact_target = '';
    	} else {
    		$contact_target = $this->link_target;
    	}
    	// get current buffer content and clean buffer
    	$content = ob_get_contents();
    	ob_clean();
    
    	// esc_url() should be used on all URLs, including those in the 'src' and 'href' attributes of an HTML element.
    	// open the bar
    	$inject = '<div id="scb-wrapper"';

    When you echo the $content, you fill up the buffer again. And if the stored ->ob_level is equal to the current ob_get_level(), then you flush and close the buffer. (If the level is not equal, you can be sure that you are not the one who opened it.)

    	}
    
    	// display it
    	echo $content;
    
    	if($this->ob_level != -1 && $this->ob_level == ob_get_level()) {
              ob_end_flush();
          }
    }
    Plugin Author Martin Stehle

    (@hinjiriyo)

    Thank you very much for sharing your thoughts! I implemented your suggestions in the currently published version 6.2. How does it work in your installation?

    If you like the plugin I would be glad about your review.

    Plugin Author Martin Stehle

    (@hinjiriyo)

    With the new version 6.3 a slight change in using the output buffer is implemented. Please report if that version works for you.

    Still getting PHP Error with 6.3

    [19-Jul-2018 17:57:19 UTC] PHP Notice: ob_clean(): failed to delete buffer. No buffer to delete in /home/content/a2pewpnas01_data02/86/3939686/html/wp-content/plugins/speed-contact-bar/public/class-speed-contact-bar.php on line 791

    And line 789 when it first opens.

    • This reply was modified 1 year, 4 months ago by cpufix2017.

    Thanks @hinjiriyo, I will be able to check it after the next week as I’m on holiday.

    @cpufix2017: It would help if you could list all your activated plugins and the name of your theme. Probably one of them closes the buffer or skips the template_redirect action.

    @hinjiriyo: to prevent @cpufix2017 error (his will result that your plugin won’t place the bar, but there won’t be an error message)

    public function include_contact_bar() {
    if ( ob_get_level() == 0) {
      // there is no opened output buffer what we could use
      return false;
    }

    @hinjiriyo: If I would be in your place, I would probably leave output buffers for this plugin. I would insert the HTML code into the wp_footer action and place it to the start of the body tag with JavaScript. Or wp_head with json encoded html and insert the code to the right place with JS.

    • This reply was modified 1 year, 4 months ago by Nextendweb.

    @nextendweb
    The error message I posted shows the plugin name “Speed Contact bar”.
    My post has also been done on the Support » Plugin: Speed Contact Bar » ob_get_clean() creates conflict

    So I’m not sure why you think I should do as you stated @cpufix2017: It would help if you could list all your activated plugins and the name of your theme. Probably one of them closes the buffer or skips the template_redirect action.

    @cpufix2017: It is a community driven support forum and anyone can help anyone, I just tried to help you. Of course it does not mean that you can’t wait for the developer to respond.

    Plugin Author Martin Stehle

    (@hinjiriyo)

    It is tricky since there is another ob related bug reported. There were no errors until ob_end_flush() or ob_flush() was implemented in the plugin. I am thinking about to remove it.

    Plugin Author Martin Stehle

    (@hinjiriyo)

    I could not reconstruct your case. Would you please do me a favor and try the current version with a small tweak and report about your experience? Of course do that only if you know PHP. Just comment out or delete the line containing ob_flush(); in the file “public/class-speed-contact-bar.php”. Will there be any difference?

Viewing 9 replies - 1 through 9 (of 9 total)
  • The topic ‘ob_get_clean() creates conflict’ is closed to new replies.