Jump to content

kicken

Gurus
  • Posts

    4,695
  • Joined

  • Last visited

  • Days Won

    177

Everything posted by kicken

  1. There's no need for your foreach() loop inside your while loop. In fact I would expect it to not work as $row['app_id'] wouldn't be an array. while($row = mysqli_fetch_array($result)) { $checked1[] = $row['app_id']; } That said, can you not just use a JOIN in your first sql query to achieve the desired results? Seems like it should be possible if your just getting ID's and re-querying.
  2. file() leaves the new lines on the end of each line by default. Each entry in your array then is going to have a newline sequence following it which is why your matches do not work. $date_array = file('test.txt', FILE_IGNORE_NEW_LINES);
  3. I do most my dev work in chrome and since they have always had that view source reload problem I got used to using Fiddler2 when I need to debug things like that. Using it you can just find whichever request your interested in and then view it's data. Works well when dealing with xhr requests and such too.
  4. Web Root and Document Root are the same thing generally. They refer to the location from which your website is served by your webserver. Any file/directory below the web root has a corresponding URL from which it can be accessed. Filesystem root is where your filesystem on your hard drive begins. Such as C:\ on windows, or '/' on linux/unix/mac. Script Root could be whatever you want it to be, it doesn't really have any particular meaning. ----- You can define however many "root" directories as you want, just so long as you know what each one is referencing. That is why they are usually prefixed with some other word and not just 'root'. I usually define an includes root, uploads root, templates root, etc: define('DOCUMENT_ROOT', dirname(dirname(__FILE__))); define('TEMPLATE_ROOT', DOCUMENT_ROOT.DIRECTORY_SEPARATOR.'templates'); define('INCLUDE_ROOT', DOCUMENT_ROOT.DIRECTORY_SEPARATOR.'includes'); define('UPLOADS_ROOT', DOCUMENT_ROOT.DIRECTORY_SEPARATOR.'Uploads'); What you just have to know and understand is that regardless of whether you define your own roots or not will have no effect on how a path is resolved unless you use those root constants in your paths. <?php require('/file.php'); ?> The / there will always refer to the filesystem root. If you want to use a different root, you have to prefix the path with the appropriate root constant: <?php require(INCLUDE_ROOT.'/file.php'); ?> Likewise in HTML. <a href="/index.php"></a> Will always refer to the web/document root. If you wanted some other root you would have to echo it out as a prefix.
  5. If you want the constant replaced with it's value, you have to concatenate it with the string, not just embed it. echo '>'.CNT_TXT_ADMIN_CLIENTES.'</a>';
  6. Root on your mac is the '/' directory. Perhaps that is labeled as 'Macintosh HD' in your file viewer. I have zero experience on mac's so I can't really say for sure how it's represented in the GUI. No, root is an absolute term, not relative. In windows, root is the drive letter, eg C:\. Since mac's and linux/unix filesystems do not have drives like windows, root is the '/' directory. In any case, root is always the very top level of the file tree. If you open a shell and run cd / it will take you to your root. You can always setup a constant/variable which points as a specific directory and consider that your app's "Root" but that does not have any effect on what the "/" prefix on a path means, and there is no way to change it. You have to prefix all your paths with the constant/variable you have setup for it to have any effect.
  7. Having a single config file to control site settings like that is still a nice thing to have. It is typically unnecessary for paths but convenient if you have other settings that may change (eg, email settings, DB settings, etc) You need to understand when your dealing with a Web path/URL and when your dealing with a filesystem path. In HTML you are always dealing with a URL path. Your link of /index.php is transformed into http://local.dev3/ (or http://www.MySite.com/ depending on how you've accessed the site). PHP generally always uses a Filesystem path unless otherwise noted in the manual. As such, '/' always references the filesystem root. Whatever you configure your virtual host to has absolutely zero effect on this, php is not restrained by it in any way. It's generally easier to just use relative paths, as they do not generally change unless you go through and restructure your site and move a bunch of files around. You can also auto-detect your root using php's magic constants. I do this generally in my global config file and use it to define a few constants to refer to other directories. Example: define('BASEDIR', dirname(dirname(dirname(__FILE__)))); define('PRIVATEDIR', BASEDIR.DIRECTORY_SEPARATOR.'private'); define('PUBLICDIR', BASEDIR.DIRECTORY_SEPARATOR.'public'); define('ERROR_LOG', PRIVATEDIR.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'errors.log'); That defines BASEDIR to point to where my site is located on the filesystem. eg, given my layout in my previous post, D:\Web\SiteA. Then I define additional constants based on that to determine the location of other directories/files. My code can use these constants when necessary. If you do build your site to use all relative paths, the above is not really necessary. Your main confusion seems to stem from your lack of understanding of when your dealing with a URL vs a Path though. You need to recognize when your dealing with each, and that there is a difference between the two and what is considered to be their 'root'.
  8. No, it should not. Your not in HTML, your in PHP. PHP is based of the filesystem root, not the web root. Your file system root is going to be at least the directory containing 05_Debbie folder, maybe higher if there are more levels. Lets try a full example. I store all my websites that I am working on in my D:\ drive on my laptop in a folder called web. D:\ web\ siteA\ private\ public\ components\ header.php index.php siteB\ private\ public\ moreSites...\ Now, I setup my virtual hosts to use the public folder under each site as the document root. So for example: http://siteA/index.php would correspond do D:\Web\siteA\public\index.php In this setup, our roots would be: Web Root: D:\Web\SiteA\public Filesystem Root: D:\ Inside index.php, we have: <?php require('/components/header.php'); ?> Since PHP uses the filesystem root, that path is going to refer to D:\components\header.php Any HTML paths such as in an image tag are interpreted as a URL, which is always run through the server and is only capable of referencing something under the server's document root. This is why a / there references the web root because the / in HTML is just a shortcut for http://siteA/
  9. Your two sorting functions are completely separate and have no relation to each other. When you call usort($productArray, 'sortElement1Asc'); your sorting the array by the date. Next, when you call usort($productArray, 'sortElement2Asc'); your sorting the array by the price, but in the process you completely overwrite the previous sorting. This second call is a completely separate process with no relation to the previous sort. What you need to do to sort by both is create one single function which will do the sorting you need. First, compare the price. If they differ, return -1 or 1 accordingly. If they are equal, move on to your second condition on the date. Compare the dates and return -1, 0, or 1 as appropriate.
  10. Web Root is not the same as the Filesystem root. The webroot is whatever the webserver is configured to use as their document root, eg $_SERVER['DOCUMENT_ROOT']. The Filesystem root is the root of the filesystem/drive (eg '/' on linux, C:\ (or relevant drive) on windows). PHP paths are based on the Filesystem layout. Since all HTML paths are run through the webserver, they are all based on the Web layout (where the root = document root). When dealing with paths in PHP, you need to know how the files relate to each other in relation to the filesystem path structure. Since PHP is not limited by the webserver's document root, you can access files and directories outside of it. This is a common method of making a private directory to store things like uploaded documents or include files.
  11. If you have a CLI build of php (not cgi) then there are three constants defined: STDIN - Input stream STDOUT - Output stream STDERR - Error stream You can use the normal file functions with these constants, such as fgets/fread. while($quit != true) { echo "Please enter the number to find "; $input = fgets(STDIN); //Do something with $input }
  12. As mentioned, the reason your example works without get and set is because PHP allows you to make new properties on the fly. One way to override this, and something I do on most of my objects, is to define __get and __set: abstract class LockedObject { public function __get($nm){ throw new Exception('Property '.$nm.' not defined'); } public function __set($nm, $v){ throw new Exception('Property '.$nm.' not defined'); } } You can use __get and __set to enforce certain rules or perform certain operations on your protected/private members. For example, say your data member needed to be of a certain object, say DateTime. You could do: class Posting extends LockedObject { protected $mPostedDate; public function __set($nm, $v){ switch ($nm){ case 'PostedDate': if (!is_object($v)){ //Assume string, try and make a new date time $v = new DateTime($v); } if (!(i$v instanceof DateTime)){ throw new Exception('PostedDate must be a DateTime object or date string.'); } break; default: parent::__set($nm, $v); } } public function __get($nm){ switch ($nm){ case 'PostedDate': return $this->mPostedDate; default: return parent::__get($nm); } } } With that, you can access the posted date property as if it were a public property ($obj->PostedDate). When you assign something to the property it will automatically validate it by attempting to convert any non-object value (for example a string such as '2011-11-25') into a DateTime. It will then only allow a valid DateTime object to be finally assigned to the property, anything else will cause an exception.
  13. It just removes what is an unnecessary check. fetch_object would return false in the case of no rows, there's no need to have a separate check for num rows=0 No, you want =, not ==. The way the condition would read is: if $result is false (ie, query failed ) or the return value of fetch_object (which gets stored in $row) is false (ie, no rows) then return false. The !$result is evaluated first, if it is true then the if is run and the function returns false. If $result is ok, then PHP will execute the ($row=$result->fetch_row()) part, which will get the first row and assign it to $row Then PHP tests if the result of that operation is false (the preceding !) and run the if causing the function to return false.
  14. The num rows check is not really necessary. Also, do not use the @ operator. It hides any errors which 99% of the time you do not want to do. Configure your script to log errors to a file rather than display them to the screen if necessary, do not just hide them all together. $result = $conn->query($query); if (!$result || !($row = $result->fetch_object())) { return false; } return $row->admin; Do as suggested, dump the value of $admin and exit the script so you can see it. Just because your script is supposed to redirect doesn't mean it has to while you debug. Just have it print debug info and die. var_dump() can be better than a direct echo as it will also show things like null/false more clearly
  15. The complex notation can be used around any variable in about any situation. It's generally not required however, except in instances where your variable name may be ambiguous or contains characters not normally allowed in a name. In your original case, without the braces: $controller->$url[1](); That code could mean two things: 1) Find the variable $url and get it's value. Use that value as the name on $controller, get it's [1]'th element then call it as a function. -or- 2) Find the variable $url and get it's [1]th element, use that as the name of a method on $controller and call it The author wants the latter, and the braces tell PHP to do exactly that. Other cases my be something like if your putting a variable in a string next to some text, eg maybe: $hiliFront = '<strong style="background: yellow;"><em>'; $hiliBack='</em></strong>'; echo "Welcome {$hiliFront}Kicken{$hiliBack}, how are you today"; //Without the braces, PHP would see the first var as $hiliFrontKicken instead of $hiliFront Or if a property on an object contains invalid characters, such as say: $sql = 'SELECT COUNT(*) FROM bleh'; $obj = mysql_fetch_object(mysql_query($sql)); echo $obj->{'COUNT(*)'}; //Though a better solution is to alias the column name
  16. No, you can't just add arguments. You can inline the array's if you want, but if your number of replacements gets large it's more readable to have them separate. str_replace(array(' ', '-'), array('cars', 'bikes'), $row['model']);
  17. No. -- and ++ work on the variable directly. Using the variable that you apply the ++/-- to elsewhere in the same statement generally falls under the category 'Undefined Behavior'. This means the computer can do whatever it wants and it'll be considered a valid response to the operation. I'm not sure if php defines this behavior or not. I know for instance C does not. The statement $a = $a--; could be interpreted as multiple different actions sequences, which each would have separate outputs. Assume $a=10 to start with, it could be: $a=10; $tmp = $a; //save the value of $a for use later. $a = $a - 1; // the -- operation $a = $tmp; //use the previous value of $a //final result is $a = 10. The -- is essentially nullified. or it could be run as: $a = 10; $a = $a; //Use the current $a; $a = $a - 1; //run the -- operation //final result is $a=9.
  18. You can use phpinfo() to check. Just make a page with the following: <?php phpinfo(); ?> The search the output for the 'magic_quotes_gpc' directive and see what the values are. While it's possible to disable it at runtime, it does not do any good. By the time your script is executed, PHP will already have collected the input data and run the magic quotes process so changing the setting has no effect.
  19. First, your examples are backwards. $a++ / $a-- is a postfix increment (or decrement). The ++ or -- comes after (post) the variable. ++$a / --$a is a prefix increment (or decrement). The ++ or -- comes before (pre) the variable. Prefix increment causes the variables value to be incremented and then returned. eg: $a=10; $b = ++$a; //is the same as $a = 10; $a = $a + 1; $b = $a; Postfix increment causes the varaibles value to be returned, then incremented after. $a = 10; $b = $a++; //is the same as $a = 10; $b = $a; $a = $a + 1; Decrement is the exact same, but subtracting one rather than adding one.
  20. I assume you want to know if the user is on cable, dsl, wifi, dial-up, etc? That's not something an IP will tell you. Some ISP's give hints about that in their reverse dns of an ip, but that's not something you can rely on, and it may not really even be accurate. You'd have to have a database on your end that could map ip ranges to connection type. Creating such a database would mean having to find out who owns what IP blocks, and what services they provide with those IPs. I have no idea if such a DB already exists that you might download/buy. Google may know.
  21. mysql_real_escape_string() is sufficient. stripslashes is unnecessary unless your host has magic_quotes_gpc enable and you need to undo that prior to processing the data. If that is the case, you should have a little script to do that as part of your script startup and which is run on every page (usually put in a file and included on ever page). You'll want to save your mysql_real_escape_string until your ready to put the value into SQL. Do all your validations and other checks prior to escaping it, as escaping it can introduce characters or conditions that may cause an otherwise valid string to fail validation. Optionally, if your validation process will ensure that a string will cause no problems (eg, if you validate a string contains only 'a'-'z' or only '0'-'9') you could skip the mysql_real_escape_string call, but continuing to do it will not hurt either.
  22. Using url re-writing, or some other method in which your requests are all routed through a single script which parses the url to grab whatever data is necessary and sends it to another script internally. In apache the easy way to do this is mod_rewrite. IIS also has a URL Rewriter module you can install. Stored procedures save a step of the DB engine having to compile the SQL and develop an execution plan. It can do this ahead of time and then just run it each time the procedure is called. For simple things like updating a user's last login time or just getting their info, this is not going to make a difference at all. For more complicated actions which involve several queries in can be beneficial. For instance, if you have a report which needs to run a number of different queries and combine the results a procedure may help. The main benefit of a procedure is to keep a task isolated in sql and it can make it easier to re-use the same process in multiple places in the code. Some places also use procedures as a way to enforce certain data requirements by only allowing an application to access the DB via a procedure, not allowing it to access the tables directly.
  23. You should be able to pull out a GUID and then use it in another query without any problem. I do that in various places in our application code with no problems at all. Just make sure your generating a valid query and that your GUID is formatted correctly when being insert into the query. The GUID should be formatted such as: '0856B94A-2BF4-476B-AFA2-44F4CCF022AF', optionally including braces on the ends: '{0856B94A-2BF4-476B-AFA2-44F4CCF022AF}' PHP Should receive it as a string without any need to explicitly convert it, and sql server should accept it in string form in a query.
  24. I spent a little time fixing up the code I had written for websockets to handle the updated protocol. Here's the code, if anyone finds it useful. It is based around PHP's Stream's api rather than the socket extension. It's not a full and complete implementation, but should be enough to get things started for anyone really interested in websockets. WebSocketConnection.class.php: <?php require __DIR__.DIRECTORY_SEPARATOR.'WebSocketMessage.class.php'; require __DIR__.DIRECTORY_SEPARATOR.'ILogger.interface.php'; class WebsocketConnection { private $mReadBuffer; protected $mProtoType; protected $mProtoVersion; protected $mState; protected $mReceivedClose; protected $mSentClose; protected $mCloseStartedOn; protected $mStream; protected $mRequestUri; protected $mHeaders; protected $mLoggers; const HANDSHAKE=1; const ESTABLISHED=2; const CLOSING=3; const CLOSED=4; const PROTO_HYBI='hybi'; const PROTO_HIXIE='hixie'; public function __get($nm){ throw new Exception('Unknown property '.$nm); } public function __set($nm,$v){ throw new Exception('Unknown property '.$nm); } public function __construct(){ $this->mState = self::CLOSED; $this->mReadBuffer = null; $this->mStream = null; $this->mHeaders=array(); $this->mRequestUri=''; $this->mLoggers=array(); $this->mReceivedClose=false; $this->mSentClose=false; $this->mCloseStartedOn=0; } public function addLogger(ILogger $logger){ $this->mLoggers[]=$logger; } private function log($str){ foreach ($this->mLoggers as $l){ $l->log($str); } } public function GetStream(){ return $this->mStream; } public function IsConnected(){ return $this->mState == self::ESTABLISHED || $this->mState == self::CLOSING; } /** * Fill the read buffer from the stream * */ protected function fillReadBuffer(){ $r = array($this->mStream); $w = $e = null; while (stream_select($r, $w, $e, 0, 0) > 0){ $this->log('Reading data from stream'); $data = fread($this->mStream, 1024); if (strlen($data)==0){ //Reading 0 data means the stream has been closed $this->Close(true); return; } $this->mReadBuffer .= $data; //$this->log('Read data: '.$data); $r = array($this->mStream); $w = $e = null; } } protected function WriteStream($str){ fwrite($this->mStream, $str); } /** * Locates the first instance of a set of strings * Returns the position in $str, optionally returns the length * of the string found in $oLen */ protected function indexOfFirst($str, $findArr, &$oLen=null){ $posArr = array(); foreach ($findArr as $f){ $posArr[] = array(strpos($str, $f), strlen($f)); } $finalPos = false; $oLen = null; foreach ($posArr as $p){ if ($p[0] !== false){ if ($finalPos === false || $finalPos > $p[0]){ $finalPos = $p[0]; $oLen = $p[1]; } } } return $finalPos; } /** * Read up to (and including) the next \r\n from the input buffer * Returns false if a full line cannot be read. * */ protected function readLine(&$line){ $pos = $this->indexOfFirst($this->mReadBuffer, array("\r\n", "\n", "\r"), $len); if ($pos !== false){ $end = $pos+$len; $line = substr($this->mReadBuffer, 0, $end); $this->mReadBuffer = substr($this->mReadBuffer, $end); return true; } return false; } /** * Reads exactly the specified number of bytes */ protected function readExactly($bytes, &$output){ if (strlen($this->mReadBuffer) > $bytes){ $output = substr($this->mReadBuffer, 0, $bytes); $this->mReadBuffer = substr($this->mReadBuffer, $bytes); return true; } return false; } /** * Peeks at the buffer by reading the requested data but not removing it from the buffer. * */ protected function peekExactly($bytes, &$output){ if (strlen($this->mReadBuffer) > $bytes){ $output = substr($this->mReadBuffer, 0, $bytes); return true; } return false; } /** * Read the opening handshake from other stream resources * */ protected function readHeaders(){ $endOfHeaders=false; do { $this->fillReadBuffer(); $curHeader=array(); while (!$endOfHeaders && $this->readLine($line)){ $line = rtrim($line, "\r\n"); if ($line==''){ $endOfHeaders=true; } else { if (substr($line, 0, 3) == 'GET'){ $resourceStart = strpos($line, ' ')+1; $resourceEnd = strpos($line, ' ', $resourceStart); $this->mRequestUri = substr($line, $resourceStart, $resourceEnd-$resourceStart); } else { if (!ctype_space($line[0])){ if (!empty($curHeader)){ $this->mHeaders[$curHeader[0]] = $curHeader[1]; } $pos = strpos($line, ':'); $curHeader[0] = rtrim(strtoupper(substr($line, 0, $pos))); $curHeader[1] = ltrim(substr($line, $pos+1)); } else { $curHeader[1] .= ' '.ltrim($line); } } } } } while (!$endOfHeaders); if ($curHeader){ $this->mHeaders[$curHeader[0]] = $curHeader[1]; } } /** * Upgrades the connection, processing the opening handshake and enabling the websocket. * */ public function DoUpgrade($stream){ if (!is_resource($stream)){ throw new InvalidArgumentException('Stream must be specified and must be a resource'); } $this->mStream = $stream; if (function_exists('stream_set_read_buffer')){ stream_set_read_buffer($this->mStream, 0); } stream_set_write_buffer($this->mStream, 0); stream_set_timeout($this->mStream, 2, 0); return $this->ProcessHandshake(); } protected function ProcessHandshake(){ $this->readHeaders(); $this->log('Headers are: '.print_r($this->mHeaders, true)); $responseCode = 101; $acceptKey = null; if (isset($this->mHeaders['SEC-WEBSOCKET-KEY1']) && isset($this->mHeaders['SEC-WEBSOCKET-KEY2'])){ $this->mProtoType = self::PROTO_HIXIE; $this->mProtoVersion = 76; } else if (isset($this->mHeaders['SEC-WEBSOCKET-KEY'])){ $this->mProtoType = self::PROTO_HYBI; $this->mProtoVersion = 17; } else { $this->log('Unknown websocket protocol.'); throw new Exception('Unknown websocket protocol'); } if (isset($this->mHeaders['SEC-WEBSOCKET-VERSION'])){ $this->mProtoVersion = intval($this->mHeaders['SEC-WEBSOCKET-VERSION']); } if ($this->mProtoType==self::PROTO_HIXIE){ while (!$this->readExactly(8, $last8)){ $this->fillReadBuffer(); } $keys = array(null, null, $last8); try { foreach (array($this->mHeaders['SEC-WEBSOCKET-KEY1'], $this->mHeaders['SEC-WEBSOCKET-KEY2']) as $n=>$val){ $digits = ''; $spaces = 0; for ($i=0; $i<strlen($val); $i++){ $c = $val[$i]; if (ctype_digit($c)){ $digits .= $c; } else if (ctype_space($c)){ $spaces++; } } if ($spaces==0){ throw new Exception('No spaces found in key. Must be at least one.'); } $keys[$n] = floatval(floatval($digits)/$spaces); } $finalKey = pack('N2a8', intval($keys[0]), intval($keys[1]), $keys[2]); $acceptKey = md5($finalKey, true); } catch (Exception $e){ $this->log('Unable to generate accept key.'); $responseCode=400; break; } } else { $key = trim($this->mHeaders['SEC-WEBSOCKET-KEY']); $key = $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; $acceptKey = base64_encode(sha1($key, true)); } if (!isset($this->mHeaders['UPGRADE']) || strcasecmp($this->mHeaders['UPGRADE'], 'websocket') != 0){ $this->log('No or Bad upgrade header'); $this->log('$this->mHeaders[uPGRADE] = '.$this->mHeaders['UPGRADE']); $this->log('strcasecmp = '.strcasecmp($this->mHeaders['UPGRADE'], 'websocket')); var_dump($this->mHeaders['UPGRADE']); $responseCode = 400; } /*if (isset($this->mHeaders['SEC-WEBSOCKET-PROTOCOL'])){ $requestedProtos = explode(',', $this->mHeaders['SEC-WEBSOCKET-PROTOCOL']); $hasValidProto = false; foreach ($requestedProtos as $p){ if ($this->mServer->IsValidProtocol($p)){ $hasValidProto = true; } } if (!$hasValidProto){ $responseCode = 406; break; } }*/ if (!$acceptKey){ $responseCode=500; } $origin = isset($this->mHeaders['ORIGIN'])?$this->mHeaders['ORIGIN']:'null'; $resource = sprintf('ws://%s%s', $this->mHeaders['HOST'], $this->mRequestUri); $this->log('Response Code is '.$responseCode); switch ($responseCode){ case 101: $response = "HTTP/1.1 101 Upgraded\r\n"; $response .= "Upgrade: WebSocket\r\n"; $response .= "Connection: Upgrade\r\n"; $response .= "Sec-WebSocket-Origin: {$origin}\r\n"; $response .= "Sec-WebSocket-Location: {$resource}\r\n"; if (isset($this->mHeaders['SEC-WEBSOCKET-PROTOCOL'])){ $response .= "Sec-WebSocket-Protocol: {$this->mHeaders['SEC-WEBSOCKET-PROTOCOL']}\r\n"; } if ($this->mProtoType==self::PROTO_HIXIE){ $response .= "\r\n{$acceptKey}"; } else { $response .= "Sec-WebSocket-Accept: {$acceptKey}\r\n"; $response .= "\r\n"; } break; case 400: $response = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n"; break; case 406: $response = "HTTP/1.1 406 Not Acceptable\r\nConnection: close\r\n\r\n"; break; case 500: default: $response = "HTTP/1.1 500 Internal Server Error\r\nConnection: close\r\n\r\n"; break; } $this->WriteStream($response); if ($responseCode == 101){ $this->mState = self::ESTABLISHED; return true; } else { fclose($this->mStream); $this->mStream = null; $this->mState = self::CLOSED; return false; } } public function Close($force=false){ if (!$this->mCloseStartedOn){ $this->mCloseStartedOn=time(); $this->log('Starting close at: '.$this->mCloseStartedOn); } if ($force || ($this->mSentClose && $this->mReceivedClose) || time()-$this->mCloseStartedOn > 10){ if ($this->mStream) fclose($this->mStream); $this->mState = self::CLOSED; $this->mStream = null; $this->log('Shutdown stream, socket is closed.'); } else { $this->mState = self::CLOSING; if (!$this->mSentClose){ $this->log('Sending close frame.'); $m = new WebSocketMessage(WebSocketMessage::TYPE_CLOSE); $this->SendMessage($m); } } } public function GetMessage(){ $this->fillReadBuffer(); $m = $this->ReadMessage(); if ($m && $m->Type == WebSocketMessage::TYPE_CLOSE){ $this->mReceivedClose = true; $this->Close(); $m = null; } return $m; } public function SendMessage(WebSocketMessage $msg){ if ($this->mProtoType == self::PROTO_HYBI){ $this->sendHybiMessage($msg); } else { $this->sendHixieMessage($msg); } if ($msg->Type == WebSocketMessage::TYPE_CLOSE){ $this->mSentClose=true; $this->Close(); } } protected function ReadMessage(){ $buff = $this->mReadBuffer; $ret=null; if ($this->mProtoType == self::PROTO_HYBI){ $ret=$this->readHybiMessage($buff); } else { $ret=$this->readHixieMessage($buff); } if ($ret){ $this->mReadBuffer = $buff; } return $ret; } protected function readHixieMessage(&$buffer){ $ret = null; if (strlen($buffer) > 0){ $type = ord($buffer[0]); if (($type & 0x80) == 0x80 && isset($buffer[1])){ $length = 0; $byteNum=1; do { $lenByte=ord($buffer[$byteNum++]); $length = ($length*128)+($lenByte&0x7F); } while (isset($buffer[$byteNum]) && ($lenByte&0x80)==0x80); if ($type == 0xFF && $length == 0){ $ret = new WebSocketMessage(WebSocketMessage::TYPE_CLOSE, null); $buffer = substr($buffer, min(strlen($buffer),2)); } else if ($length > 0){ $length = min(strlen($buffer),$length); $buffer = substr($buffer, $length); } } else if (($type&0x80) == 0){ $payload=array(); $byteNum=1; while (isset($buffer[$byteNum]) && ord($buffer[$byteNum]) != 0xFF){ $payload[] = $buffer[$byteNum++]; } if ($type == 0){ $ret = new WebSocketMessage(WebSocketMessage::TYPE_TEXT, implode('', $payload), count($payload)); $buffer = substr($buffer, $byteNum+1); } } } return $ret; } protected function readHybiMessage(&$buffer){ $ret = null; do { if (strlen($buffer) > 2){ $bytes = substr($buffer, 0, 2); $buffer = substr($buffer, 2); $byte = ord($bytes[0]); $flags = ($byte&0xF0)>>4; $opcode = $byte&0x0F; $byte = ord($bytes[1]); $ismasked = ($byte&0x80)>>7; $payloadLen = $byte&0x7F; $this->log(sprintf("Flags: %d; Opcode: %d; Masked: %d; Length: %d", $flags, $opcode, $ismasked, $payloadLen)); $validLen=false; switch ($payloadLen){ case '126': if (strlen($buffer) > 2){ $payloadLenBytes = substr($buffer, 0, 2); $buffer = substr($buffer, 2); $payloadLen = unpack('nlen', $data); $payloadLen = $payloadLen['len']; $validLen=true; } break; case '127': if (strlen($buffer) > { $payloadLenBytes = substr($buffer, 0, ; $buffer = substr($buffer, ; $data = unpack("Nhi/Nlo", $payloadLenBytes); $payloadLen = ($data['hi']<<32)|$data['lo']; $validLen=true; } break; default: /* $payloadLen is itself. */ } if ($opcode == 0x8){ //Disable mask on closing frames $ismasked=0; } if ($ismasked && strlen($buffer) > 4){ $maskKey = substr($buffer, 0, 4); $buffer = substr($buffer, 4); $this->log('Mask key: '.$maskKey); } else if ($ismasked){ break; //No mask given, but one should be given. } if (strlen($buffer) >= $payloadLen){ $payload = substr($buffer, 0, $payloadLen); $buffer = substr($buffer, $payloadLen); //$this->log('Payload (pre-mask): '.$payload); if ($ismasked){ $payload = $this->applyMask($payload, $payloadLen, $maskKey); //$this->log('Payload (post-mask): '.$payload); } $ret = new WebsocketMessage($opcode, $payload, $payloadLen); if ($flags&0x8 == 0){ $obj = $this->readHybiMessage($buffer); if ($obj){ $ret->Data .= $obj->Data; $ret->DataLength += $obj->DataLength; $buffer = $newBuffer; } } } } } while (false); return $ret; } protected function applyMask($payload, $payloadLen, $mask){ $newPayload=''; for ($i=0; $i<$payloadLen; $i++){ $keyByte = unpack('cchar', $mask[$i%4]); $keyByte = $keyByte['char']; $newPayload .= chr(ord($payload[$i]) ^ $keyByte); } return $newPayload; } protected function sendHybiMessage($msg){ $len = $msg->DataLength; if ($len > 125){ $len = 126; } $packet = pack('cc', 0x80 | $msg->Type, 0x00 | $len); if ($len == 126){ $packet .= pack('n', $msg->DataLength); } $packet .= $msg->Data; $this->WriteStream($packet); } protected function sendHixieMessage($msg){ if ($msg->Type == WebSocketMessage::TYPE_CLOSE){ $packet = chr(0xff).chr(0x00); } else { $utf8 = iconv('ISO-8859-1', 'UTF-8', $msg->Data); $packet = chr(0).$utf8.chr(0xFF); } $this->WriteStream($packet); } } ILogger.interface.php <?php interface ILogger { public function Log($str); } WebSocketMessage.class.php <?php class WebSocketMessage { public $Data; public $DataLength; public $Type; const TYPE_TEXT = 0x1; const TYPE_BINARY = 0x2; const TYPE_CLOSE = 0x8; public function __construct($Type, $Data='', $Len=null){ $this->Data = $Data; $this->Type = $Type; $this->DataLength = $Len?:strlen($Data); } public function __get($nm){ throw new Exception('Unknown property '.$nm); } public function __set($nm,$v){ throw new Exception('Unknown property '.$nm); } } And a sample server script: <?php require 'WebSocketConnection.class.php'; class EchoLogger implements ILogger { public function log($str){ echo rtrim($str), "\r\n"; } } $server=stream_socket_server('tcp://0.0.0.0:8010'); echo "Listening for connections\r\n"; while ($client=stream_socket_accept($server)){ $ws = new WebsocketConnection(); $ws->addLogger(new EchoLogger()); echo "Upgrading connection\r\n"; if ($ws->DoUpgrade($client)){ echo "Upgrade complete, entering loop\r\n"; do { $r = array($ws->GetStream()); $w = $e = null; if (stream_select($r, $w, $e, 10, 0) > 0){ if ($m = $ws->GetMessage()){ $m->Data = md5($m->Data); $m->DataLength = strlen($m->Data); $ws->SendMessage($m); } } } while($ws->IsConnected()); } else { echo "Upgrade failed\r\n"; } }
  25. Yes, what you want is a factory pattern. Your Root class does not extend any of the classes, it is it's own separate class. So your diagram would look like: Base Class | Root Class /\ | / \ | Class A Class B | Root class just uses an instance of either a or b, and decides which one at runtime based on some condition. Our payment stuff is setup such as: interface IPaymentGateway { public function ProcessCreditCard($params); //... } class PaypalPaymentGateway implements IPaymentGateway { public function ProcessCreditCard($params){ //Paypal methods here } } class PaygistixPaymentGateway implements IPaymentGateway { public function ProcessCreditCard($params){ //Paygistix methods here } } class PaymentGateway { public static function GetImplementation($impl){ switch ($impl){ case 'paypal': return new PaypalPaymentGateway(); case 'paygistix': return new PaygistixPaymentGateway(); default: throw new InvalidArgumentException('Invalid payment gateway type'); } } } In the site config file we have a constant defined: PAYMENT_GATEWAY_IMPL which specifies which gateway to use. Then in the code where we need to do a payment: $pg = PaymentGateway::GetImplementation(PAYMENT_GATEWAY_IMPL);
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.