First, I should re-iterate that dealing with the TWS socket is not like dealing with web services. It is not a request/response model: it is a publish/subscribe model and the socket is not closed between subscription/unsubscription requests.
The process is something like this:
1) You open a socket.
2) You subscribe to a symbol(s)
3) Periodically, on the open socket you will receive messages pertaining to the market data you have subscribed to.
The whole time the socket is open.
A typical web request would open a socket to the web server and then the server would serve the requested page and then close the socket (these days that isn't strictly true). The web server won't know you the next time you ask for a page (hence the need for tricks like cookies) You have to open a new socket all over again and the server will send you a new page. The web server isn't processing things on your behalf in between your requests. PHP code isn't running in between your requests. Nothing is happening in between your requests. If you don't make a page request for a hundred years, ther server will just be sitting there doing nothing (assuming no other person is accessing the web server).
If you already knew the above, then fair enough. If you didn't and you can't grasp the consequences of why it's important, you will soon enough. If you aren't writing your PHP code as a web application then you can ignore what I just said.
Having said all of that I should also say that if you want to pursue this course you will be writing a lot of code just to get access to the IP API from PHP and there may be better options.
That's because you aren't expected to write this code. You're expected to use one of the supplied APIs e.g. Java, C++ etc.
To make an equivalent API in PHP will require you to replicate what IB has made for the other languages. The alternative is to use PHP to call the C++ API.
If you still want to go ahead. This should get you going in the right direction:
To connect to TWS you will have to do something like this:
Code:
def eConnect_0(self, socket, clientId):
self.m_dos = DataOutputStream(socket.getOutputStream())
self.send(self.CLIENT_VERSION)
self.m_reader = self.createReader(self, DataInputStream(socket.getInputStream()))
self.m_serverVersion = self.m_reader.readInt()
debug("Server Version: %s", self.m_serverVersion)
if self.m_serverVersion >= 20:
self.m_TwsTime = self.m_reader.readStr()
debug("TWS Time at connection: %s", self.m_TwsTime)
if self.m_serverVersion < self.SERVER_VERSION:
self.eDisconnect()
self.m_anyWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg())
return
if self.m_serverVersion >= 3:
self.send(clientId)
self.m_reader.start()
self.m_connected = True
This function takes a socket object. Using that socket object it grabs an output stream and then sends the client version to TWS (self.CLIENT_VERSION - this is like a constant that is defined elsewhere - in this case it points to an integer 45)
It then grabs an input stream from the socket and reads an integer - this is TWS' response - it will be the TWS version in terms of the API.
The subsequent code checks to see if the client code is compatible with the server (TWS) that it's trying to connect to.
The code above was found in the Python port of the Java code.
http://code.google.com/p/ibpy/source/browse/trunk/ib/ext/EClientSocket.py
You'll have to replicate this entire code in your PHP version.
More importantly, you'll have to replicate the EReader code which is the code responsible for reading messages coming from the socket and decoding it into meaningful things such as market data or account updates etc.
Again, the Python port of the Java code is here:
http://code.google.com/p/ibpy/source/browse/trunk/ib/ext/EReader.py
Here is a list of the different message types taken directly from EReader:
Code:
TICK_PRICE = 1
TICK_SIZE = 2
ORDER_STATUS = 3
ERR_MSG = 4
OPEN_ORDER = 5
ACCT_VALUE = 6
PORTFOLIO_VALUE = 7
ACCT_UPDATE_TIME = 8
NEXT_VALID_ID = 9
CONTRACT_DATA = 10
EXECUTION_DATA = 11
MARKET_DEPTH = 12
MARKET_DEPTH_L2 = 13
NEWS_BULLETINS = 14
MANAGED_ACCTS = 15
RECEIVE_FA = 16
HISTORICAL_DATA = 17
BOND_CONTRACT_DATA = 18
SCANNER_PARAMETERS = 19
SCANNER_DATA = 20
TICK_OPTION_COMPUTATION = 21
TICK_GENERIC = 45
TICK_STRING = 46
TICK_EFP = 47
CURRENT_TIME = 49
REAL_TIME_BARS = 50
FUNDAMENTAL_DATA = 51
CONTRACT_DATA_END = 52
OPEN_ORDER_END = 53
ACCT_DOWNLOAD_END = 54
EXECUTION_DATA_END = 55
DELTA_NEUTRAL_VALIDATION = 56
TICK_SNAPSHOT_END = 57
If you look at the EReader class you'll see that it's mostly just a big switch/if/else if block that decodes the incoming data from the socket into one of the above and constructs the relevant kinds of objects out of the data e.g. orders and contracts (for price ticks though the data is passed across as is pretty much)
Good luck.