# MVS38 - Servidor 3270 ###### tags: `estudos` `linux` `Docker` `php` Possível servidor livre para testes: docker run -it seanchickenninja/mainframe https://asciinema.org/a/162008 Repo para geracao de container com TK4 https://github.com/RattyDAVE/docker-ubuntu-hercules-mvs ```bash= docker run -dit --name tk4- \ -p 3270:3270 -p 8038:8038 \ rattydave/docker-ubuntu-hercules-mvs:latest ``` **HERC01** is a fully authorized user with full access to the RAKF users and profiles tables. The logon password is ==CUL8TR==. **HERC02** is a fully authorized user without access to the RAKF users and profiles tables. The logon password is ==CUL8TR==. **HERC03** is a regular user. The logon password is ==PASS4U==. **HERC04** is a regular user. The logon password is ==PASS4U==. **IBMUSER** is a fully authorized user without access to the RAKF users and profiles tables. The logon password is ==IBMPASS==. This account is meant to be used for recovery purposes only. https://www.youtube.com/user/moshe5760/ https://hub.docker.com/r/rattydave/docker-ubuntu-xrdp-mate-custom/ ```php= <?php /** * @package extensions\php3270 */ //namespace extensions; /** * Classe para maniputar terminais 3270. * * Classe que implementa em PHP a execução de comandos e * leitura de informações em telas de terminais 3270. * É implementado usando o programa s3270 (Unix/Linux), sendo * assim o mesmo é necessário para o uso desta classe. * @see http://x3270.bgp.nu/s3270-man.html http://x3270.bgp.nu/s3270-man.html * * @author Murilo Klock Ferreira <murilo.ferreira@oi.net.br> * * @version 0.1 */ class php3270 { /** * vetor com a definição dos ponteiros de leitura e escrita * @var array vetor com a definição dos ponteiros de leitura e escrita */ var $descriptorspec = array( 0 => array("pipe","r"), 1 => array("pipe","w"), 2 => array("pipe","w") ); /** * vetor com os ponteiros de leitura e escrita * @var array vetor com os ponteiros de leitura e escrita */ var $pipes=array(); /** * Variável para guardar o resource obtido com a abertura do s3270 * @var resource resource para o s3270 */ var $process=""; /** * Variável para armazenar a tela com os dados * @var array armazena em um vetor os dados lidos na tela do terminal 3270 */ var $screen =""; /** * Variável para guardar o número de linhas do terminal 3270 * @var int número de linhas do terminal 3270 */ var $lines=""; /** * Variável para guardar o número de colunas do terminal 3270 * @var int número de colunas do terminal 3270 */ var $columns=""; /** * Variável para guardar o texto de erro do terminal 3270 * @var string descrição do erro no terminal 3270 */ var $error=""; /** * Variável para armazenar os dados de status do terminal 3270 * @var array vetor os dados de status do terminal 3270 */ var $status_msg=array(); /** * Variável para ligar ou desligar o debug * @var boolean liga ou desliga o debug */ var $debug=false; /** * Variável para guardar o status da conexão, conectado ou desconectado. * @var boolean conectado ou desconectado */ var $connected=true; /** * Variável para guardar o tempo de espera, quando necessário. * O padrão é 0, não esperastatus da conexão, conectado ou desconectado. * @var int tempo em microsegundos */ var $waittime=0; /** * Construtor da classe. Abre um processo abilitando leitura e escrita ao mesmo. * Força os ponteiros para escrita e leitura para modo sem bloqueio. * Caso haja sucesso na abertura do processo, abre uma conexão com o servidor. * @see s3270::connect função para abrir conexão com servidor. * * @param string $hostname Nome do servidor ou endereço IP * @param int $port porta a ser usada para conextar * * @return boolean */ function __construct($hostname, $port=23) { $this->process = proc_open('/usr/bin/s3270', $this->descriptorspec, $this->pipes, null, null); stream_set_blocking($this->pipes[0], 0); stream_set_blocking($this->pipes[1], 0); #$this->debug=true; if(is_resource($this->process)) { $this->connect($hostname, $port); return true; } else { $this->error="Erro de resource\n"; echo $this->error; return false; } } /** * Envia comando Clear ao servidor * * @return void */ final public function clear() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $this->sendCommand("Clear()"); } /** * Abre a conexão ao servidor dentro do processo s3270. * * @param string $hostname Nome do servidor ou endereço IP * @param int $port porta a ser usada para conextar * * @return boolean */ private function connect($hostname, $port=23) { fwrite($this->pipes[0], "connect(".$hostname.":".$port.")\n"); $this->waitUnlock(); $this->waitInputField(); $this->waitReturn(); //fwrite($this->pipes[0], "enter()\n"); //$this->waitReturn(); } /** * Encerra conexão com servidor 3270 * * @return void */ function disconnect() { #$this->sendCommand('PF(10)'); #$this->waitReturn(); #$this->sendCommand('PF(12)'); #$this->waitReturn(); #@fwrite($this->pipes[0], "Disconnect()\n"); $this->sendCommand("Disconnect()"); $retorno=""; $tela=array(); //$this->waitReturn(); } /** * Ascii(row,col,rows,cols) * ou * Ascii(row,col,length) * ou * Ascii(length) * * Exibe uma representação em texto ASCII da tela. * Cada linha é precedida pelo texto "data: ", e não existem caracteres de * controle. * * Se quatro argumentos são informados, uma região retangular * da tela é a saída. * * Se três argumentos são informados, $length caracteres são a saída, * começando pela linha e coluna especificada. * * Se apenas o argumento length é informado, este número de caracteres é * retornado como saída, començando pela posição atual do cursor. * * Se não são informados argumentos, a tela inteira é a saída. */ function ascii() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $argumentos = func_num_args(); $lista = func_get_args(); if($argumentos > 4) die("Fatal, número de argumentos para ascii maior do que 4."); foreach($lista as $a=>$b) $lista[$a]=$b--; #die("Lista:#".implode(',',$lista)."#"); $this->sendCommand("Ascii(".implode(',',$lista).")"); #return $this->rectangle( implode(',',$lista) ); #fwrite($this->pipes[0], "Ascii(".implode(',',$lista).")\n"); } /** * Envia um comando ao terminal 3270 * * @param string $cmd comando a ser enviado * @link http://x3270.bgp.nu/s3270-man.html#Actions http://x3270.bgp.nu/s3270-man.html#Actions * * @return boolean */ final public function sendCommand($cmd) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if(is_resource($this->process)) { if($this->debug) echo " escrevendo ".'fwrite($this->pipes[0], '.$cmd.')\n");'."<br />\n"; fwrite($this->pipes[0], $cmd."\n"); #fwrite($this->pipes[0], "ascii()\n"); //$this->waitUnlock(); #$this->esperaCampo(); #$this->waitReturn(); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Envia um texto ao terminal 3270 * * @param string $texto comando a ser enviado * @param int [$row] opcional linha onde sera colocado o texto. A primeira linha é 1. * @param int [$col] opcional coluna onde sera colocado o texto. A primeira coluna é 1. * @link http://x3270.bgp.nu/s3270-man.html#Actions http://x3270.bgp.nu/s3270-man.html#Actions * * @return boolean */ final public function sendString($string,$row=false,$col=false) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if( $row!=false and $col!=false ) { $this->moveCursor($row,$col); } if(is_resource($this->process)) { if($this->debug) echo " escrevendo ".'fwrite($this->pipes[0], "string("'.$string.'")\n");'."<br />\n"; fwrite($this->pipes[0], "string(".$string.")\n"); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Aguarda que um campo de entrada de informações aparece no buffer de leitura * * @return boolean */ final public function waitInputField() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if(is_resource($this->process)) { fwrite($this->pipes[0], "Wait(InputField)\n"); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Aguarda até que o teclado seja desbloqueado * * @return boolean */ final public function waitUnlock() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if(is_resource($this->process)) { fwrite($this->pipes[0], "Wait(Unlock)\n"); #fwrite($this->pipes[0], "enter\n"); #fwrite($this->pipes[0], "ascii()\n"); #$this->readScreen(); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Aguarda até que haja dados no buffer de leitura * * @return boolean */ final public function waitOutput() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if(is_resource($this->process)) { fwrite($this->pipes[0], "Wait(Output)\n"); #fwrite($this->pipes[0], "enter\n"); #fwrite($this->pipes[0], "ascii()\n"); #$this->readScreen(); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Espera até que o número de linhas de dados definidas na aplicação 3270 * seja recebido * * * @param int $linhas número de linhas. Padrão 24 linhas * * @return boolean */ final public function waitReturn($rows=false) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $this->status_msg=array(); if(is_resource($this->process)) { while(true) { $return = fgets($this->pipes[1]); if( $this->debug===true ) echo "\n\n".$return."\n\n"; $re='/([U|L|E])\s([F|U])\s([P|U])\s(C\(.*\)|N)\s([I|L|C|P|N])\s([2-5])\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s(0x[0-9]+)\s([0-9\.\-]+)/'; if( preg_match($re,$return,$tmp) ) { if( $this->debug===true ) echo "\n\n".$return."\n\n"; if( isset($tmp[1]) ) $this->status_msg['keyboard_state'] =$tmp[1]; if( isset($tmp[2]) ) $this->status_msg['screen_formatting']=$tmp[2]; if( isset($tmp[3]) ) $this->status_msg['field_protection'] =$tmp[3]; if( isset($tmp[4]) ) $this->status_msg['connection_state'] =$tmp[4]; if( isset($tmp[5]) ) $this->status_msg['emulator_mode'] =$tmp[5]; if( isset($tmp[6]) ) $this->status_msg['model_number'] =$tmp[6]; if( isset($tmp[7]) ) $this->status_msg['number_of_rows'] =$tmp[7]; if( isset($tmp[8]) ) $this->status_msg['number_of_cols'] =$tmp[8]; if( isset($tmp[9]) ) $this->status_msg['cursor_row'] =$tmp[9]; if( isset($tmp[10]) ) $this->status_msg['cursor_col'] =$tmp[10]; if( isset($tmp[11]) ) $this->status_msg['window_id'] =$tmp[11]; if( isset($tmp[12]) ) $this->status_msg['command_exec_time']=$tmp[12]; } #if( $this->debug===true ) print_r( $this->status_msg); if(!$rows and !empty($this->status_msg['number_of_rows'])) $rows=$this->status_msg['number_of_rows']; elseif(!$rows) $rows=24; if( isset($this->status_msg['keyboard_state']) and $this->status_msg['keyboard_state']=='E' ) $this->clear(); if( preg_match( '/ok/',$return) ) { #echo "\n\n".$return."\n\n"; #if( $this->debug===true ) print_r( $this->status_msg); $this->readScreen($rows); return true; } elseif( preg_match( '/error/',$return) ) { $this->readScreen($rows); $this->error="Erro ao conectar ao servidor MainFrame\n"; $this->connected=false; return false; } elseif( preg_match( '/locked/is',$return) ) { $this->reset(); } elseif( preg_match( '/limpe/is',$return) ) { $this->clear(); } elseif( preg_match( '/wait/is',$return) ) { $this->waitUnlock(); } } } else { $this->error="Erro de resource\n"; echo $this->error; return false; } } /** * Envia uma ação denominada Program Function (função de programa) * que pode se um número entre 1 e 24 (PF(1) até PF(24)) * * * @param int $n número da ação (entre 1 e 24). * * @return boolean */ final public function pf($n) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if( !is_numeric($n) and ($n<1 or $n>24) ) { $this->error="Função de programa deve ser um número entre 1 e 24."; return false; } $this->sendCommand("PF(".$n.")"); } /** * Lê o número definido de linhas de dados definidas na aplicação 3270 * * * @param int $linhas número de linhas. Padrão 24 linhas * * @return boolean */ final public function readScreen($rows=false) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $this->screen = array(); if(!$rows) $rows=$this->status_msg['number_of_rows']; $inicio = false; $retorno = ""; if(is_resource($this->process)) { #fwrite($this->pipes[0], "Wait(Output)\n"); #fwrite($this->pipes[0], "ascii()\n"); $this->waitOutput(); $this->ascii(); if( $this->debug===true ) { echo 'Número de linhas em $this->screen: '.count($this->screen)."\n"; echo 'Número de linhas em $rows: '.$rows."\n"; } while ( count($this->screen) < $rows) { $retorno = fgets($this->pipes[1]); if( preg_match( '/locked/is',$retorno) ) { $this->reset(); } elseif( preg_match( '/limpe/is',$retorno) ) { $this->clear(); } elseif( preg_match( '/wait/is',$retorno) ) { $this->waitUnlock(); } #if( $this->debug===true ) { # echo "Retorno: ".$retorno."\n"; #} #if( count($this->screen)>1 and preg_match('/^data:(.*)/i',$retorno,$tmp) and !$inicio ) { # if( trim($tmp[1]) == '' ) continue; #} #else $inicio=false; if( !empty($retorno) and preg_match('/^data/',$retorno) ) $this->screen[] = $retorno; #fwrite($pipes[0], "ascii()\n"); usleep($this->waittime); } if( $this->debug===true ) { echo "Vamos imprimir o Vetor com o retorno\n"; print_r($this->screen); } return true; } else { $this->error="Erro de resource\n"; echo $this->error; return false; } } /** * rectangle(row,col,rows,cols) * ou * rectangle(row,col,length) * ou * rectangle(length) * * Exibe uma representação em texto ASCII da tela. * Cada linha é precedida pelo texto "data: ", e não existem caracteres de * controle. * * Se quatro argumentos são informados, uma região retangular * da tela é a saída. * * Se três argumentos são informados, length caracteres são a saída, * começando pela linha e coluna especificada. * * Se apenas o argumento length é informado, este número de caracteres é * retornado como saída, començando pela posição atual do cursor. * * Se não são informados argumentos, a tela inteira é a saída. */ final public function rectangle() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $argumentos = func_num_args(); $lista = func_get_args(); $saida = ''; if($argumentos > 4) die("Fatal, número de argumentos para ascii maior do que 4."); if( $argumentos== 4 ) { $lista[0]=($lista[0]-1); $lista[2]=($lista[2]-1); } if( $argumentos== 3 ) $lista[0]=$lista[0]-1; $tmp = $this->screen; foreach($tmp as $a => $b) $tmp[$a]=preg_replace('/^data:/','',$b); if($argumentos==4) { foreach($tmp as $a=>$b) { if($a<$lista[0] or $a>$lista[2]) continue; $saida.=substr($b,$lista[1],($lista[3]-$lista[1]))."\n"; } } if($argumentos==3) { $saida=substr($tmp[$lista[0]],$lista[1],$lista[2]); } elseif($argumentos==1 and !empty($lista[0])) { $saida=substr($b,0,$lista[0]); } elseif($argumentos==0) { $saida=implode("\n",$tmp); } return $saida; } /** * Envia comando Reset ao servidor * * @return void */ final public function reset() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $this->sendCommand("Reset()"); } /** * Envia comando EraseInput ao servidor. Apaga todos valores em campos * de entrada de dados * * @return void */ final public function eraseInput() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $this->sendCommand("EraseInput()"); } /** * Movo cursor para a posição determinada pela linha e pela coluna informados * @param int $row * @param int $col * @return boolean */ final public function moveCursor($row,$col) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; if( $row!=false and $col!=false ) { $row--; $col--; } $this->sendCommand("MoveCursor(".$row.", ".$col.")"); #fwrite($this->pipes[0], "MoveCursor(".$row.", ".$col.")\n"); #$this->waitUnlock(); return true; } /** * Converte os dados lidos do formato Array para String * * * @return string $strTela Dados da tela do terminal 3270 em formato texto. */ final public function screenToString() { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $strTela=''; if( isset($this->screen) and is_array($this->screen) ) { $tmp = $this->screen; foreach($tmp as $a => $b) $tmp[$a]=preg_replace('/^data:/','',$b); $strTela = implode( "", $tmp ); } return $strTela; } /** * Função para aguardar que determinado texto apareça na tela (buffer) * * @param string string a ser esperado * * @return string $screen texto da tela */ final public function waitString ($string) { if($this->debug) echo "Função: ".__FUNCTION__."\n"; $x = false; $g = false; $tela = ""; $linha=1; while ($x == false) { usleep(1000); while (false !== ($mydat = fgets($this->pipes[1]))) { echo $mydat."\n"; $tela.=$mydat; if (preg_match("/".$string."/i", $mydat)) { $g = true; } if ($g == true) { while (false !== ($mydat = fgets($this->pipes[1]))) { $tela.=$mydat; #echo $mydat."\n"; } $x = true; break 2; } } #fwrite($pipes[0], "ascii()\n"); } return $tela; } /** * Destrutor da classe. Fecha os ponteiros de leitura e escrita abertos * e fecha o processo. */ function __destruct() { foreach ($this->pipes as $pipe) { @fclose($pipe); } @proc_close($this->process); } } ?> ``` ```php= <?php /** * @package extensions\php3270 */ //namespace extensions; /** * Classe para maniputar terminais 3270. * * Classe que implementa em PHP a execução de comandos e * leitura de informações em telas de terminais 3270. * É implementado usando o programa s3270 (Unix/Linux), sendo * assim o mesmo é necessário para o uso desta classe. * @see http://x3270.bgp.nu/s3270-man.html http://x3270.bgp.nu/s3270-man.html * * @author Murilo Klock Ferreira <murilo.ferreira@oi.net.br> * * @version 0.1 */ class sac extends php3270 { /** * Abre uma aplicação dentro da sessão aberta no mainframe 3270 * * @param string $aplicacao Número ou Nome da aplicação a ser aberta * * @return boolean */ final public function abreAplicacao ($aplicacao) { if(is_resource($this->process)) { $this->sendString($aplicacao); $this->sendCommand("Enter()"); $this->waitUnlock(); $this->waitOutput(); //$this->waitInputField(); $this->waitReturn(); #$this->waitString("MENU PRINCIPAL"); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Abre uma sessão no mainframe 3270 * * @param string $sessao Número ou Nome da sessão a ser aberta * * @return boolean */ final public function abreSessao ($sessao) { if(is_resource($this->process)) { fwrite($this->pipes[0], "string(".$sessao.")\n"); fwrite($this->pipes[0], "Enter()\n"); #fwrite($this->pipes[0], "ascii()\n"); $this->waitUnlock(); $this->waitInputField(); $this->waitReturn(); #$this->waitReturn(); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Envia credenciais de acesso ao sistema * * * @param string $usuario usuário de acesso * @param string $senha senha de acesso * * @return boolean */ final public function login($user,$pass) { if(is_resource($this->process)) { $this->sendString($user,16,35); #fwrite($this->pipes[0], "string(".$user.")\n"); $this->sendString($pass,17,35); #fwrite($this->pipes[0], "string(".$pass.")\n"); $this->sendcommand("Enter()"); #fwrite($this->pipes[0], "Enter\n"); $this->waitUnlock(); $this->waitInputField(); $this->waitReturn(24); } else { $this->error="Erro de resource\n"; echo $this->error; return false; } return true; } /** * Encerra conexão com servidor 3270 * * @return void */ function logout() { $this->pf(10); $this->waitOutput(); $this->waitReturn(); $this->waitInputField(); $this->sendString('LOGOFF'); $this->sendCommand('Enter()'); $this->waitOutput(); $this->waitReturn(); $this->waitInputField(); $retorno=""; $tela=array(); } } ``` --- # dfsdf ## fdgdf