+ if( $text === false ) {
+ return false;
+ }
+ $stripped = str_replace( "\r", "", $text );
+ $normalized = UtfNormal::cleanUp( $stripped );
+ return $normalized;
+ }
+
+ private function getTextSpawned( $id ) {
+ wfSuppressWarnings();
+ if( !$this->spawnProc ) {
+ // First time?
+ $this->openSpawn();
+ }
+ while( true ) {
+
+ $text = $this->getTextSpawnedOnce( $id );
+ if( !is_string( $text ) ) {
+ $this->progress("Database subprocess failed. Respawning...");
+
+ $this->closeSpawn();
+ sleep( $this->failureTimeout );
+ $this->openSpawn();
+
+ continue;
+ }
+ wfRestoreWarnings();
+ return $text;
+ }
+ }
+
+ function openSpawn() {
+ global $IP, $wgDBname;
+
+ $cmd = implode( " ",
+ array_map( 'wfEscapeShellArg',
+ array(
+ $this->php,
+ "$IP/maintenance/fetchText.php",
+ $wgDBname ) ) );
+ $spec = array(
+ 0 => array( "pipe", "r" ),
+ 1 => array( "pipe", "w" ),
+ 2 => array( "file", "/dev/null", "a" ) );
+ $pipes = array();
+
+ $this->progress( "Spawning database subprocess: $cmd" );
+ $this->spawnProc = proc_open( $cmd, $spec, $pipes );
+ if( !$this->spawnProc ) {
+ // shit
+ $this->progress( "Subprocess spawn failed." );
+ return false;
+ }
+ list(
+ $this->spawnWrite, // -> stdin
+ $this->spawnRead, // <- stdout
+ ) = $pipes;
+
+ return true;
+ }
+
+ private function closeSpawn() {
+ wfSuppressWarnings();
+ if( $this->spawnRead )
+ fclose( $this->spawnRead );
+ $this->spawnRead = false;
+ if( $this->spawnWrite )
+ fclose( $this->spawnWrite );
+ $this->spawnWrite = false;
+ if( $this->spawnErr )
+ fclose( $this->spawnErr );
+ $this->spawnErr = false;
+ if( $this->spawnProc )
+ pclose( $this->spawnProc );
+ $this->spawnProc = false;
+ wfRestoreWarnings();
+ }
+
+ private function getTextSpawnedOnce( $id ) {
+ $ok = fwrite( $this->spawnWrite, "$id\n" );
+ //$this->progress( ">> $id" );
+ if( !$ok ) return false;
+
+ $ok = fflush( $this->spawnWrite );
+ //$this->progress( ">> [flush]" );
+ if( !$ok ) return false;
+
+ $len = fgets( $this->spawnRead );
+ //$this->progress( "<< " . trim( $len ) );
+ if( $len === false ) return false;
+
+ $nbytes = intval( $len );
+ $text = "";
+
+ // Subprocess may not send everything at once, we have to loop.
+ while( $nbytes > strlen( $text ) ) {
+ $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) );
+ if( $buffer === false ) break;
+ $text .= $buffer;
+ }
+
+ $gotbytes = strlen( $text );
+ if( $gotbytes != $nbytes ) {
+ $this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes ");
+ return false;
+ }
+
+ // Do normalization in the dump thread...