我的小工具-远程读卡器web客户端(PHP+LUA)

简介: 我的小工具-远程读卡器web客户端(PHP+LUA)

  晚上睡不着,想着白天工作上的事,解决一个现场读卡问题就需要出趟差值得吗。想着在公司就能把现场的卡给读写诊断了,能让数据跑路就别让人跑路,说干就干。


本工具是在浏览器中以Lua脚本的形式对CPU卡,M1卡就行读、写等各种操作,配和使用改造过后的E711读卡器。


远端把读卡器接到电脑上,并运行读写卡服务。告知客户端IP地址和端口,并放上卡。客户端调用相关指令,运行脚本,输出结果。


   远程读卡器就是一个普通usb口或串口的读卡器,如E711读卡器。配合一个电脑软件作为tcp读写卡服务。这样可以在公司电脑上运行客户端程序连到服务器上,服务器端操控现场的读卡器。之前做保定公交老卡兼容,让现场寄卡过来,结果拖了好久,卡也没寄过来。说是卡片管理严格,老年卡,学生卡需要从系统上从新办卡。于是让现场同事配合抓下包,读取一下卡上数据,但现场同事连串口助手都没听说过,指望不上了。最后没办法,还是出差跑去一趟,做了些很简单的事。回来想想,其实可以做一个远程读卡器,在公司把现场的卡给操作了。再封装一些读卡的客户端接口,可以实现远程仿真调试程序读卡消费逻辑 ,或者实现一完全软件模拟的pos机。之前用java做过一个读写卡工具,但是只能在本地电脑上读写卡。


交通部卡测试消费成功的lua脚本指令:


--192.168.157.135/test3/runcode.php
--读卡服务地址
ip= "192.168.157.135"
--读卡服务端口
port = 5050
--连接到读卡服务
ret = CONNECT(ip,port)                     --建立连接
-------------------------------------------  CPU卡操作
ret,rcv = S_SFI("\x3F\x00",1)              --选择PSAM卡应用3F00
ret,rcv = R_BFile(0x15,0,0,1)              --读取PSAM卡15文件
ret,rcv = R_BFile(0x16,0,0,1)              --读取PSAM卡16文件
if ret == 0x9000 then
  PasmTID = string.sub(rcv,1,12)
  print("pasmTID:"..PasmTID)
end
ret,rcv = S_AID("\xA0\x00\x00\x06\x32\x01\x01\x05",0x08,0)      --选择交通部应用
ret,rcv = R_BFile(0x15,0,0,0)              --读取卡片0x15文件
if ret == 0x9000 then
  MakeCardId = string.sub(rcv,1,16)
  CardASN = string.sub(rcv,25,25+16-1)
  print(rcv)
  print("MakeCardId:"..MakeCardId)
  print("CardASN:"..CardASN)
end
ret,rcv = R_BFile(0x16,0,0,0)
ret,rcv = R_BFile(0x17,0,0,0)    
ret,rcv = S_SFI("\x80\x11",1)              --选择交通部PSAM卡应用
ret,rcv = APDU("805C030204",0)              --读取余额
--消费初始化
cmd = '805001020B'
index = '01'
money = '00000001'
cmdstr = cmd..index..money..PasmTID
print("xiao fei chu shi hua:")
ret,rcv = APDU(cmdstr,0)   --消费初始化
if ret == 0x9000 then
  PullCTC = string.sub(rcv,9,9+4-1)  --脱机交易序号
  KeyVer = string.sub(rcv,19,19+2-1)
  KeyDrk = string.sub(rcv,21,21+2-1)
  Icc =  string.sub(rcv,23,23+8-1)  --随机数
  print("PullCTC:"..PullCTC)
  print("KeyVer:"..KeyVer)
  print("KeyDrk:"..KeyDrk)
  print("Icc:"..Icc)
end
cmd = '8070000024'
time ='20161128170231'
cmdstr = cmd..Icc..PullCTC..money..'06'..time..KeyVer..KeyDrk..CardASN..MakeCardId 
ret,rcv = APDU(cmdstr,1)   --PSAM卡算MAC
if ret == 0x9000 then
  TTC = string.sub(rcv,1,8)  --脱机交易序号
  MAC1 = string.sub(rcv,9,9+8-1)
  print("TTC:"..TTC)
  print("MAC1:"..MAC1)
end
cmd = '805401000F'
cmdstr = cmd..TTC..time..MAC1
ret,rcv = APDU(cmdstr,0)
DISCONNECT()                --断开连接


   要远程读写卡得有个后台服务去操控远程的读卡器。有了后台读写卡服务,客户端不能只是接口,得简单好用,于是有了这个web端。


附截图:


截图1,运行效果



截图2,相关指令介绍:



截图3,后台文件



截图4,后台读写卡服务显示的收发日志:



后台的解析lua脚本的文件lua_test.c


//包含LUA的头文件,用来支持脚本
#include <stdio.h>
#include "lib/lua-5.3.1/lua.h"  
#include "lib/lua-5.3.1/lualib.h"  
#include "lib/lua-5.3.1/lauxlib.h"   
#include "lib/includes.h"
#define PICC_ADD                    0xC1            //加
#define PICC_SUB                    0xC0            //减
#define PICC_RESTORE                0xC2            //恢复
#define PICC_KEYA                   0x60            //KEY A
#define PICC_KEYB                   0x61            //KEY B
#define PICC_NULL                   0x00            //不校验KEY
lua_State* L;  
U08 gCardSN[8]; //物理卡号
U32 ICF_SelectAID( const char *AID, U32 ilen, U32 ich )
{
    U32 rcode;
    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xA4;   //INS
    gCmdBuffer[2] = 0x04;   //P1
    gCmdBuffer[3] = 0x00;   //P2
    gCmdBuffer[4] = ilen;   //Lc
    CurCalc_DataCpy( gCmdBuffer+5, (U08*)AID, ilen );
    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, ilen+5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }
    if( Grcv_Len < 2 )  
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );
    return rcode;
}
U32 ICF_SelectSFI( const char *SFI, U32 ich )
{
    U32 rcode;
    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xA4;   //INS
    gCmdBuffer[2] = 0x00;   //P1
    gCmdBuffer[3] = 0x00;   //P2
    gCmdBuffer[4] = 0x02;   //Lc
    CurCalc_DataCpy( gCmdBuffer+5, (U08*)SFI, 2 );
    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, 2+5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }
    if( Grcv_Len < 2 )
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );
    return rcode;
}
U32 ICF_ReadBinaryFile( U08 SFI, U08 Offset, U08 BytesToRead, U32 ich )
{
    unsigned short rcode;
    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xB0;   //INS
    gCmdBuffer[2] = 0x80 | ( SFI & 0x1F );  //P1
    gCmdBuffer[3] = Offset; //P2
    gCmdBuffer[4] = BytesToRead;    //Le
    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, 5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }
    if( Grcv_Len < 2 )                                          //长度判断
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );
    return rcode;
}
int LConnect(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    printf("Connecting...\n");
    const char * ipaddr = luaL_checklstring(L,1,&le);
    //printf("cmd is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值,并检查  
    int port = luaL_checkinteger(L,2); 
    printf("ServerIP:%s,Port:%d\n", ipaddr,port);
    ret = Connect(ipaddr,port);
    lua_pushnumber(L,ret); 
    return 1;
}
int LDisConnect(lua_State* L)
{
    printf("Close connect!\n");
    Com_Dev_Disconnect( 0 );  
    return 1;
}
int LTxData(lua_State* L)
{
    int ret = 0;
    unsigned int len = 0;
    size_t le = 0;
    unsigned char buf[1024];
    unsigned char outbuf[2048];
    memset(buf, 0, 1024);
    memset(outbuf, 0, 2048);
    //从L栈中取出索引为1的数值,并检查  
    const char * txdata = luaL_checklstring(L,1,&le);
    //printf("tx is %s,le is %d\n",txdata,le);  
    StrToHex( (char*)txdata, le, buf );
    ret = Com_Dev_TxData( buf, le/2, 0, 0 );
  if( ret != 0 )
  { DEF_SysCard_Debug; return ret; }
    ret = Com_Dev_RxData( buf, &len,  1024, 0, 0 ); 
  if( ret != 0 )
  { DEF_SysCard_Debug; return ret; }
  HexToStr(buf,len,(char*)outbuf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)outbuf,strlen((char*)outbuf));
    return 2;
}
int LTxData1(lua_State* L)
{
    int ret = 0;
    unsigned int len = 0;
    size_t le = 0;
    unsigned char buf[1024];
    unsigned char outbuf[2048];
    memset(buf, 0, 1024);
    memset(outbuf, 0, 2048);
    //从L栈中取出索引为1的数值,并检查  
    const char * txdata = luaL_checklstring(L,1,&le);
   // printf("tx is %s,le is %d\n",txdata,le);  
    //StrToHex( (char*)txdata, le, buf );
    ret = Com_Dev_TxData1( (unsigned char*)txdata, le, 0, 0 );
  if( ret != 0 )
  { DEF_SysCard_Debug; return ret; }
    ret = Com_Dev_RxData1( buf, &len,  1024, 0, 0 ); 
  if( ret != 0 )
  { DEF_SysCard_Debug; return ret; }
  //HexToStr(buf,len,(char*)outbuf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,len);
    return 2;
}
int LAPDU_Exchange(lua_State* L)
{
  int ret = 0;
  size_t le = 0;
  unsigned char buf[520];
  memset(buf, 0, 520);
  //从L栈中取出索引为1的数值,并检查  
    const char * cmd = luaL_checklstring(L,1,&le);
    //printf("cmd is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值,并检查  
    int ich = luaL_checkinteger(L,2); 
    StrToHex( (char*)cmd, le, gCmdBuffer );
    ret = ICC_APDU_Exchange( ich, gCmdBuffer, le/2, gpRcvBuffer, &Grcv_Len, 260 );
    if( Grcv_Len < 2)
  { return 1;}
    ret = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;
}
int LSelectAID(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    unsigned char buf[520];
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值,并检查  
    const char * aid = luaL_checklstring(L,1,&le);
    //printf("aid is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值,并检查  
    int len = luaL_checkinteger(L,2); 
    int ich = luaL_checkinteger(L,3); 
    ret = ICF_SelectAID( aid, len, ich );
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;
}
int LSelectSFI(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    unsigned char buf[520];
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值,并检查  
    const char * sfi = luaL_checklstring(L,1,&le);
    //printf("aid is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值,并检查  
    int ich = luaL_checkinteger(L,2); 
    ret = ICF_SelectSFI( sfi, ich );
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;
}
int LReadBinaryFile( lua_State* L )
{
    int ret = 0;
    unsigned char buf[520];
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值,并检查  
    int sfi =  luaL_checkinteger(L,1); 
    int oft =  luaL_checkinteger(L,2);
    int rlen = luaL_checkinteger(L,3);
    int ich =  luaL_checkinteger(L,4); 
    ret = ICF_ReadBinaryFile(sfi,oft,rlen,ich);
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    //stackDump(L);
    return 2;
}
//获取CPU或M1卡的物理卡号
int LGetPhySn( lua_State* L )
{
    int ret = 0;
    unsigned char buf[20];
    unsigned char buf1[20];
    memset(buf,0,20);
    memset(buf1,0,20);
    ret = ICC_MiOne_GetPhySn(buf);
    memcpy(gCardSN,buf,8);//保存全局物理卡号
    HexToStr(buf,8,(char*)buf1);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf1,strlen((char*)buf1));
    //stackDump(L);
    return 2;
}
//M1卡扇区读
int LBlkRead( lua_State* L )
{
    int ret = 0;
    size_t le = 0;
    unsigned char rbuf[50];
    unsigned char sbuf[50];
    unsigned char key[16];
    unsigned char cmd=0;
    int block   =  luaL_checkinteger(L,1); 
    const char * keys = luaL_checklstring(L,2,&le);
    int keytype =  luaL_checkinteger(L,3); //密码类型,0,不校验 1,A码,2,B码
    memset(rbuf,0,50);
    memset(sbuf,0,50);
    StrToHex( (char*)keys, le, key );
    cmd = PICC_KEYA;
    if(keytype == 1)
    { cmd = PICC_KEYA; }
    else if(keytype == 2)
    { cmd = PICC_KEYB; }
    ret = ICC_MiOne_BlkRead(block,cmd,key, gCardSN, rbuf );
    HexToStr(rbuf,16,(char*)sbuf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)sbuf,strlen((char*)sbuf));
    //stackDump(L);
    return 2;
}
//M1卡扇区写
int LBlkWrite( lua_State* L )
{
    int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char wbuf[50];
    unsigned char key[16];
    unsigned char cmd=0;
    int block   =  luaL_checkinteger(L,1); 
    const char * wbufs = luaL_checklstring(L,2,&le);
    const char * keys = luaL_checklstring(L,3,&le1);
    int keytype =  luaL_checkinteger(L,4); //密码类型,0,不校验 1,A码,2,B码
    memset(wbuf,0,50);
    StrToHex( (char*)wbufs, le, wbuf );
    StrToHex( (char*)keys, le1, key );
    cmd = PICC_KEYA;
    if(keytype == 1)
    { cmd = PICC_KEYA; }
    else if(keytype == 2)
    { cmd = PICC_KEYB; }
    ret = ICC_MiOne_BlkWrite(block,cmd,key, gCardSN, wbuf );
    lua_pushinteger(L,ret); 
    //stackDump(L);
    return 1;
}
//DES加密
int LDES_Encrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
  unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);
    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );
  CurCalc_DES_Encrypt( inkey, indata, outdata );
  HexToStr(outdata,8,(char*)str_out);
    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,16);
    //stackDump(L);
    return 1;
}
//DES解密
int LDES_Decrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
  unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);
    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );
  CurCalc_DES_Decrypt( inkey, indata, outdata );
  HexToStr(outdata,8,(char*)str_out);
    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,16);
    //stackDump(L);
    return 1;
}
//3DES加密
int LDES_3Encrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
  unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);
    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );
  CurCalc_3DES_Encrypt( inkey, indata, outdata );
  HexToStr(outdata,16,(char*)str_out);
    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,32);
    //stackDump(L);
    return 1;
}
//3DES解密
int LDES_3Decrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
  unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);
    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );
  CurCalc_3DES_Decrypt( inkey, indata, outdata );
  HexToStr(outdata,16,(char*)str_out);
    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,32);
    //stackDump(L);
    return 1;
}
U32 MathDesMac( U08 *pbuf, U32 length, U08 *key,U08 checktype )
{
  U32 len ;
  U08 mac[8], mac1[8];
  len = length ;
  if( checktype == 0 )
  {
    CurCalc_DES_MAC64( (SINGLE_DES_ENCRYPTION|ZERO_CBC_IV), key, 0, pbuf, len ,  mac );
    memcpy( pbuf+len, mac, 8 );
    return 0 ;
  }
  else
  {
    //暂存源校验码
    memcpy( mac1, pbuf+len-8, 8 ) ; 
    CurCalc_DES_MAC64( (SINGLE_DES_ENCRYPTION|ZERO_CBC_IV), key, 0, pbuf, len-8 ,  mac) ; 
    if ( memcmp( mac, mac1, 8 ) == 0x00 )
    {
      return 0 ;    //校验产生的校验码和原校验码相等, 校验成功
    }
    else
    {
      return 1 ;      //校验产生的校验码和原校验码不等, 校验失败
    }
  } 
}
int LMathDesMac( lua_State* L )
{
    int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[1024];
  unsigned char str_out[2048];
    const char * str_indata = luaL_checklstring(L,1,&le);
  int   inlen   =  luaL_checkinteger(L,2);
  const char * str_inkey = luaL_checklstring(L,3,&le1);
  int   type   =   luaL_checkinteger(L,4);
    StrToHex( (char*)str_indata, le, indata );
  StrToHex( (char*)str_inkey, le1, inkey );
  ret = MathDesMac( indata, inlen,inkey,type );
  memset(str_out,0,2048);
  HexToStr(indata,inlen+8,(char*)str_out);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,strlen((char*)str_out));
    //stackDump(L);
    return 1;
}
int main( void )  
{  
    //初始化全局L  
    L = luaL_newstate();  //创建lua的栈 
    //打开库  
    luaL_openlibs(L);  
    //把函数压入栈中  
    //lua_pushcfunction(L, add);  
    //设置全局ADD  
    //lua_setglobal(L, "ADD");  
    //lua_register(L,"ADD",add);
    lua_pushcfunction(L, LConnect);  
    //设置全局ADD  
    lua_setglobal(L, "CONNECT"); 
    lua_register(L,"DISCONNECT", LDisConnect); 
    lua_register(L,"TxData",LTxData);
  lua_register(L,"TxData1",LTxData1);
    lua_register(L,"APDU", LAPDU_Exchange);  
    lua_register(L,"S_AID",LSelectAID); 
    lua_register(L,"S_SFI",LSelectSFI); 
    lua_register(L,"R_BFile",LReadBinaryFile);
    lua_register(L,"G_SN",LGetPhySn);
    lua_register(L,"R_Block",LBlkRead);
    lua_register(L,"W_Block",LBlkWrite);
  lua_register(L,"DES_Enc",LDES_Encrypt);
    lua_register(L,"DES_Dec",LDES_Decrypt);
  lua_register(L,"DES_3Enc",LDES_3Encrypt);
    lua_register(L,"DES_3Dec",LDES_3Decrypt);
  lua_register(L,"MathDesMac",LMathDesMac);
    //加载我们的lua脚本文件  
    if(luaL_loadfile(L,"test.lua"))  //载入lua脚本,是通过fopen打开的,
    {  
        printf("error,failed to analysis script!\nmaybe syntax error!\n");  
    }  
    //安全检查  
    lua_pcall(L,0,0,0); //这个函数会执行lua脚本 
    //push进lua函数  
   // lua_getglobal(L, "mylua1"); 
   // lua_pcall(L,0,0,0);   
    printf("end my lua script,finish!\n"); 
    lua_close(L); //关闭lua的栈  
    return 0;  
}  


php后台的处理原理:


compile.php


<?php
header('Content-Type:json; charset=UTF-8');
set_time_limit(0);
//var_dump($_POST);
$str= $_POST['code'];
//echo $str;
file_put_contents("test.lua",$str);
$flv_cmd="lua_test.exe >out.txt";
exec($flv_cmd);
if(file_exists("out.txt"))
{
  $txt1 = file_get_contents("out.txt");
  $err ="ok";
  $txt =iconv("GB2312","UTF-8//IGNORE",$txt1); //将编码从GB2312转成UTF-8
  //echo $txt; 
}
else
{
  $txt ="output err!\n";
  $err ="exec err!\n";
}
$json = array("output"=>$txt,"langid"=>"17","code"=>"print(\"Hello World!\")","errors"=>$err,"time"=>"01\n");
//var_dump($json);
$result = json_encode($json);
//var_dump($result);
$output = $result;
echo $output; 
?>


后台库文件的makefile:


########################################
#makefile
########################################
#编译主程序
BINARY  := lua_test
OBJ_DIR := 
CC= gcc
LD= ld
CFLAGS= -std=c99 -Wall -g
LDSCRIPT= -lmycom -lws2_32 -liconv -lmyfile  -lmycard -lmyup -lmycalc -lmyblkfile -llua
LDFLAGS= -Llib 
SRC  = $(wildcard *.c)
DIR  = $(notdir $(SRC))
OBJS = $(patsubst %.c,$(OBJ_DIR)%.o,$(DIR))
#OBJS=  main.o myutils.o  inirw.o  cmdpboc.o cputest.o bustcp.o ansrec.o m1cmd.o m1api.o m1test.o upcash.o myother.o getsys.o
#CFLAGS=-std=c99
#@echo Building lib...
#$(call make_subdir)
.PHONY: clean lib
all:  prebuild  $(BINARY).exe
prebuild:
@echo Building app...
$(BINARY).exe : $(OBJS)
@echo Generating ...
$(CC) -o $(BINARY).exe $(OBJS) $(LDFLAGS) $(LDSCRIPT) 
@echo OK!
$(OBJ_DIR)%.o : %.c
$(CC) -c $(CFLAGS) $< -o  $@
clean:
rm -f $(OBJ_DIR)*.o
@echo Removed!


相关文章
|
7月前
|
JavaScript 前端开发 API
PHP 发展简史:从个人工具到互联网基石
PHP 起源于 1994 年,由 Rasmus Lerdorf 为简化网页开发而创建,后逐步演变为功能强大的编程语言。从最初的个人工具到支撑全球 77.4% 的服务器端脚本市场,PHP 凭借易用性、稳定性和广泛的生态支持,在 Web 开发领域占据重要地位。经历 PHP 6 的挫折后,PHP 7 实现性能飞跃,如今已更新至 PHP 8.2,持续为 WordPress、Facebook、Wikipedia 等大型项目提供动力。PHP 的发展历程,不仅是一部技术演进史,更映射了互联网时代的变迁。
386 8
|
6月前
|
NoSQL API PHP
PHP-Casbin:一个让开发者不再为权限控制 “重复造轮子” 的工具
PHP-Casbin 是一个轻量、灵活的开源权限框架,支持 ACL、RBAC、ABAC 等多种模型,帮助 PHP 开发者高效解决权限控制难题。它具备跨框架、跨语言、动态权限、多租户隔离等能力,适用于电商、SaaS、政企系统等复杂场景,让开发者摆脱重复造轮子,提升项目安全与可维护性。
365 0
|
7月前
|
运维 数据可视化 C++
2025 热门的 Web 化容器部署工具对比:Portainer VS Websoft9
2025年热门Web化容器部署工具对比:Portainer与Websoft9。Portainer以轻量可视化管理见长,适合技术团队运维;Websoft9则提供一站式应用部署与容器管理,内置丰富开源模板,降低中小企业部署门槛。两者各有优势,助力企业提升容器化效率。
504 1
2025 热门的 Web 化容器部署工具对比:Portainer VS Websoft9
|
5月前
|
存储 监控 算法
基于 PHP 布隆过滤器的局域网监控管理工具异常行为检测算法研究
布隆过滤器以其高效的空间利用率和毫秒级查询性能,为局域网监控管理工具提供轻量化异常设备检测方案。相比传统数据库,显著降低延迟与资源消耗,适配边缘设备部署需求,提升网络安全实时防护能力。(238字)
234 0
|
8月前
|
网络协议 Shell PHP
简单的php版本nacos客户端
这是一个简单的 PHP 版本 Nacos 客户端,支持服务注册、配置发布、服务发现等功能。通过 Composer 安装,提供服务端与客户端示例代码,可快速集成至项目中。适用于基于 Nacos 的微服务架构开发,帮助实现服务治理与配置管理。
301 10
|
10月前
|
XML 安全 前端开发
一行代码搞定禁用 web 开发者工具
在如今的互联网时代,网页源码的保护显得尤为重要,特别是前端代码,几乎就是明文展示,很容易造成源码泄露,黑客和恶意用户往往会利用浏览器的开发者工具来窃取网站的敏感信息。为了有效防止用户打开浏览器的 Web 开发者工具面板,今天推荐一个不错的 npm 库,可以帮助开发者更好地保护自己的网站源码,本文将介绍该库的功能和使用方法。 功能介绍 npm 库名称:disable-devtool,github 路径:/theajack/disable-devtool。从 f12 按钮,右键单击和浏览器菜单都可以禁用 Web 开发工具。 🚀 一行代码搞定禁用 web 开发者工具 该库有以下特性: • 支持可配
1001 22
|
8月前
|
SQL 敏捷开发 安全
PHP 的精髓:灵活高效,为 Web 而生
PHP 的精髓:灵活高效,为 Web 而生
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
1139 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
500 20
|
Web App开发 IDE 测试技术
Selenium:强大的 Web 自动化测试工具
Selenium 是一款强大的 Web 自动化测试工具,包括 Selenium IDE、WebDriver 和 Grid 三大组件,支持多种编程语言和跨平台操作。它能有效提高测试效率,解决跨浏览器兼容性问题,进行性能测试和数据驱动测试,尽管存在学习曲线较陡、不稳定等缺点,但其优势明显,是自动化测试领域的首选工具。
1088 17
Selenium:强大的 Web 自动化测试工具