2

I am trying to write a simple application with wxPHP that pings IPs from a file using exec('ping') command.

I want the results to show up in the GUI one by one as they get pinged in the background so I'm doing the exec('ping') command in a thread.

But I get very strange errors and behavior. The problem is I can't reproduce the errors. Sometimes the program works totally fine. Sometimes it crashes in the thread. Sometimes it crashes when it is sending the event. etc.

Here are the errors I get when I run the program from command line:

C:\Users\SH\Desktop>wxphp pinger.wxphp
PHP Notice:  Undefined property: wxHtmlWindow::$parent in Unknown on line 0
PHP Fatal error:  Call to a member function setPingResults() on null in Unknown
on line 0

C:\Users\SH\Desktop>wxphp pinger.wxphp
PHP Notice:  Undefined property: wxHtmlWindow::$parent in Unknown on line 0
PHP Fatal error:  Call to a member function setPingResults() on null in Unknown
on line 0

C:\Users\SH\Desktop>wxphp pinger.wxphp
PHP Notice:  Undefined property: wxHtmlWindow::$parent in Unknown on line 553649674
PHP Fatal error:  Call to a member function setPingResults() on null in Unknown
on line 553649674

And this is my code:

<?php

if(!extension_loaded('wxwidgets'))
{
    dl('wxwidgets.' . PHP_SHLIB_SUFFIX);
}

define('EVT_PINGDONE',wxNewEventType());


class myPing extends wxThread
{
    function __construct($parent)
    {
        parent::__construct(wxTHREAD_JOINABLE);

        $this->parent =  $parent;
    }

    function Entry()
    {
        $addresses = file($this->parent->btnBrowse->GetPath(),FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
        foreach($addresses as $k => $address){

            $results = exec("ping $address");

            $this->parent->setPingResults($results);

            $evt = new wxCommandEvent(EVT_PINGDONE);
            $this->parent->QueueEvent($evt);
        }

        $this->parent->onThreadDone();

        return;
    }
}

class mythFrame extends wxFrame {

    function __construct( $parent=null ){
        parent::__construct ( $parent, wxID_ANY, 'Pinger', wxDefaultPosition, new wxSize( 600,400 ), wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );

        $this->SetSizeHints( wxDefaultSize, wxDefaultSize );

        $bSizer2 = new wxBoxSizer( wxHORIZONTAL );

        $this->button = new wxButton( $this, wxID_ANY, "Ping", wxDefaultPosition, new wxSize(300, 40), 0 );
        $bSizer2->Add($this->button, 0, wxALL|wxEXPAND, 5);

        $bSizer1 = new wxBoxSizer( wxVERTICAL );

        $this->btnBrowse = new wxFilePickerCtrl( $this, wxID_ANY, 'C:\Users\SH\Desktop\stuff\servers.txt', "Select a file", "*.*", wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE );
        $bSizer1->Add( $this->btnBrowse, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );

        $this->html = new wxHtmlWindow( $this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
        $bSizer1->Add( $this->html, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );

        $bSizer1->Add( $bSizer2, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );

        $this->SetSizer( $bSizer1 );
        $this->Layout();

        $this->Centre( wxBOTH );

        // Connect Events
        $this->button->Connect( wxEVT_COMMAND_BUTTON_CLICKED, array($this, "hndlrButton") );
        $this->Connect(wxEVT_TIMER, array($this, "onTimer"));
        $this->Connect(EVT_PINGDONE, array($this, 'updateText'));

        $this->pingThread = new myPing($this);
        $this->m_timer = new wxTimer($this);
        $this->pingResults = '';

    }

    function updateText($event){

        $this->html->AppendToPage($this->pingResults.'<br>');
    }

    function onTimer(){
        if($this->threadDone == true){
            $this->m_timer->Stop();
            $this->button->Enable();
            $this->btnBrowse->Enable();
            $this->html->AppendToPage('<br>Finished.<hr>');

            while($this->pingThread->IsRunning()){}
            $this->pingThread->Delete();

            $this->pingThread = new myPing($this);
        }
    }

    function onThreadDone(){
        $this->threadDone = true;
    }

    function setPingResults($results){
        $this->pingResults = $results;
    }


    function hndlrButton( $event ){
        $this->threadDone = false;
        $this->m_timer->start(3000);
        $this->button->Disable();
        $this->btnBrowse->Disable();

        $this->pingThread->Create();
        $this->pingThread->Run();
    }

}

$myFrame = new mythFrame();
$myFrame->show();
wxEntry();

?>

And this is the errors I get in windows error log:

Faulting application name: wxphp.exe, version: 5.6.9.0, time stamp: 0x55765568
Faulting module name: ntdll.dll, version: 6.1.7601.18247, time stamp: 0x521eaf24
Exception code: 0xc0000005
Fault offset: 0x0000000000052f86
Faulting process id: 0x3c4
Faulting application start time: 0x01d0b6675e88094f
Faulting application path: C:\Program Files\wxPHP\php\wxphp.exe
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
Report Id: 9cd6fe5e-225a-11e5-b316-f46d04f70903

Faulting module changes depending on whether i call php functions or call exec() in the thread Entry(). But the exception code is always 0xc0000005.

One weird thing that is consistent in errors is errors like

Undefined property wxHtmlWindow::$parent 

If you read the code you realize that there is no such call at all. Actually $parent is only accessed in the thread. I have got similar errors with other functions in the thread. It seems like the application doesn't realize it is in the thread and $this in the thread points to the main frame object.

I guess something is terribly wrong with my code or maybe with wxPHP. This program was not working last night, then started working this morning. Then I added an icon and some background colors to it and it suddenly is giving me errors again.

Other info

  • Doesn't work on:

    Windows 7-64bit - wxphp-3.0.2.0-php5.6-x64.exe

    Windows 7-32bit - wxphp-3.0.2.0-php5.4-x86

  • The example thread.wxphp application bundled with the wxPHP package doesn't work either.
  • However both my code and the example app work fine on Linux (Linux Mint-32bit - php5-wxwidgets_3.0.2.0_i386).
  • When I remove both exec() and QueueEvent() from the thread Entry() I don't get any errors.

Does anyone have any idea what's going on here?

halfer
  • 19,824
  • 17
  • 99
  • 186
Pouria P
  • 565
  • 1
  • 8
  • 21

1 Answers1

1

I'm the maintainer of wxPHP and I would advice to use the PHP pthreads extension for multithreading given that this extension properly handles threading with the PHP zendengine. The wxThread class was automatically wrapped by the wxPHP source generator and it may need further development to properly work.

JGM
  • 38
  • 5
  • Thanks JGM. I installed pthreads but i'm getting this error when i try to access GUI objects in the thread: `Fatal error: Failed to get the native object for wxButton::GetLabel`. I found a similar issue on github to which you had answered. So i installed thread safe versions of everything _php-5.6-ts-x64_ and _pthreads-5.6-ts-x64_ and _wxphp-5.6-ts-x64 (PECL dll)_ but i'm still getting the same error. I also installed _wxphp-3.0.0.0-x64-ts_ package from sourceforge but that also gives me the same error. – Pouria P Jul 08 '15 at 20:02