Jump to content

kicken

Gurus
  • Posts

    4,704
  • Joined

  • Last visited

  • Days Won

    179

Everything posted by kicken

  1. That's the idea. You'd just do something like $reviewHtml = $template->render($review, [ 'plaintext' => false ]); In the Symfony based sites I create I use twig for just about all the template needs I have, whether it be full pages, email messages or just small snippets. I've not yet needed to do anything like your html vs non-html split but if I ever needed to I'd probably go for either a macro or custom function solution, which ever seemed most appropriate.
  2. Correct, the rewind is not necessary, the file pointer begins at the start of the file in that mode. fread advances the file pointer by the length of the data read, so it will be just past the last byte you read. In your case at the end of the file since you're reading everything. Like fread, fwrite advances the pointer by the amount of data written, so the pointer would be just after the last byte written. In your case that would be the end of the file since you're starting with a blank file. Of the two rewinds you have you only need one of them. ftruncate does not care about the file pointer's position so whether your rewind before or after it doesn't matter from an implementation point of view. I prefer to rewind after it as I feel it makes it more obvious what the code is doing. While not necessary in your code, you might also want to look at fseek, this lets you move the file pointer arbitrarily. That is useful if you're dealing with file formats where you can calculate the offset to data (eg, fixed length records). You can also use it and ftell (or fstat) as an alternative to filesize if you have a pointer to a file but not path. fseek($fp, 0, SEEK_END); $filesize = ftell($fp);
  3. filesize Your $filesize is only going to be correct the first time the function is called. After that you'll get the cached value back. Either clear the cache or read the file in a way that doesn't depend on obtaining the file size.
  4. Because it's possible that flock fails for reasons other than the file already being locked. The way the default blocking behavior essentially works is it will only keep retrying as long as the error returned indicates that the file is already locked. If some other error occurs it'll just fail entirely. The PHP manual doesn't really expand on all the possible errors. If you look at the underlying flock or fcntl function you can get an idea of what other kinds of situations might cause it to fail.
  5. It's been removed in PHP7, so no it's not something you can just ignore. At 5.5 (which is already past it's end-of-life date) it's not a major problem but it will become a major problem when you finally get to a modern version of PHP. So how major it is depends on how long you wait to get PHP upgraded the rest of the way. Regardless, make sure you fix it soon and don't ignore it / forget about it.
  6. The warning is because indexing an object like an array is just a shorthand for calling the offsetGet method of the ArrayAccess interface. That method returns the data stored under the given index by value so changes made to it will not persist. To have the change persist you have to re-assign the index the new changed value so that the offsetSet method is called. You can see this warning if you create your own object that implements ArrayAccess and try to do the same: <?php class MyStorage implements ArrayAccess { private $map; public function offsetExists($n){ return isset($this->map[$n]); } public function offsetGet($n){ return $this->map[$n]; } public function offsetSet($n, $v){ $this->map[$n] = $v; } public function offsetUnset($n){ unset($this->map[$n]); } } $s = new MyStorage(); $s['blah'] = ['a' => 1, 'b' => 2, 'c' => 3]; var_dump($s['blah']); $s['blah']['a'] = 10; var_dump($s['blah']);
  7. You could try implementing a stream wrapper but not sure how well that'd work with react/json. Your wrapping class sounds more or less like my JSONStream class from an earlier example.
  8. No, but by binding your parameter multiple times you can add a second condition that is always true. WHERE ci.id < ? AND (? IS NULL OR ci.cat_id = ?) $next24item->bind_param('iii', $lastItemID, $category_id, $category_id); If $category_id is null then the first condition ? IS NULL will always be true and cause the second condition to be ignored. If $category_id is not null then ? IS NULL will always be false and the second condition will be evaluated.
  9. Phones typically auto-capitalize the first letter of text you enter into a field. That may be what is causing your problem. Comparisons in PHP are case sensitive, 'Hot' is not the same as 'hot'. You could use strtolower to force the value entered to lowercase prior to your comparison to resolve the issue. If that doesn't fix things then var_dump the value and test each device to compare the results.
  10. Numbers that begin with a 0 are octal based numbers. I'd guess you get the error due to running a 32-bit version of PHP, in which case 070000000000 is larger than PHP can handle as an integer. On a related note, don't try and treat phone numbers as actual numbers, treat them a strings. Just because some value only consists of digits doesn't mean it needs to be treated as an integer type.
  11. I generally use /var/www/example.com/public_html as my document root format. That keeps it nice and organized by domain. Sub domains end up in a folder under the domain, eg sub.example.com would be located at /var/www/example.com/sub/public_html. I'll adjust the document root if it works out better as something else. For example on a Symfony based site I'd point the root to the web/ folder. I don't really see the point in the extra /magical at the end of your example path, seems unnecessary.
  12. You need to use separate <VirtualHosts> for each domain you want to have. I do not use vagrant so I have no idea if you can configure multiple domains through it or if you'd have to edit the configuration files yourself. You'd end up with something like this: <VirtualHost *:80> ServerName magical.com DocumentRoot /vagrant/magical.com/public </VirtualHost> <VirtualHost *:80> ServerName myproject.com DocumentRoot /vagrant/myproject.com/public </VirtualHost> You'll also need to ensure that your magical.com and myproject.com resolve to the VM's IP so they connect properly. You can change your host's hosts file to change what the names resolve too. Rather than override actual domain names what I prefer to do is create .local equivalents. For example magical.local, myproject.local. That leaves me with the ability to visit the actual .com's if necessary.
  13. That niche final class is just one particular implementation of the given interface. class GDImageManipulator implements ImageManipulator { } Maybe later you'll create a new separate implementation that does things differently but still accomplishes the same fundamental task. class ImageMagickImageManipulator implements ImageManipulator { } In the ImageManipulator case the interface represents an object that can perform a variety of image related tasks. Essentially an image manipulator service. You give it an image and it'll do various things to it. $manipulator = new GDImageManipulator(); $manipulator->rotate($someImage, 90); If you wanted to instead create a style where you have an image class which has functions to manipulate it you could use something that conveys that meaning a bit better, maybe ManipulableImage. class Image implements ManipulableImage { } $image = new Image('somefile.jpg'); $image->rotate(90); It comes down to what style of API you want to build, which is why I suggested starting with that step. Just write up some pseudo-code for how you think you'd want everything to work then use that the develop your interfaces and final implementations.
  14. kicken

    linux command sed

    The test.txt, file is not supposed to change, that's the backup in case you messed up. The original test.txt is the one that gets changed. kicken@web1:~$ echo 'Visit www.example.com today!' > test.txt kicken@web1:~$ sed -i, s,www,the,g test.txt kicken@web1:~$ cat test.txt Visit the.example.com today! kicken@web1:~$ cat test.txt, Visit www.example.com today! kicken@web1:~$
  15. I've never been a big fan of contrived examples like animals, shapes, etc for teaching things like this. They can help provide a rough idea of the purpose of an interface but they don't always help with teaching how to actually use them in real code. I'd suggest instead combining some of these types of tutorials with digging around in actual real-world code that uses interfaces (or whatever) so you can learn not only the purpose of an interface but also when people might choose to use an interface. Whether the class is final or will be extended isn't really relevant to whether or not you want to apply an interface to it. You decide if the interface should be applied by deciding whether you want that class to provide the behavior/api the interface defines. Interfaces don't really describe what something is, they describe what something can do. So in your example you'd define your Wheelie interface and apply it to whatever is capable of that action. Interfaces also don't need to describe a specific action, the can describe a collection of actions that are related (eg, a service). For example maybe you have ImageManipulator interface that provides methods like resize, crop, greyscale, blur etc. If you're writing code and trying to determine if you should make an interface or not, think about whether it might be possible to have multiple implementations of some action. If yes, you might consider an interface. If no, probably not worth it. When designing the interface, think about how you want code to use your classes and then define that as an interface. For example just write out the end-user code until you're happy with how that looks, then write your interface to match that, then write the actual implementation to match the interface. For example, say you need some system to manage tokens for use with things like CSRF, password resets, etc. Write code that might use that system until you're happy with how it works. $tm = $container['token_manager']; $length = 16; $expires = (new DateTime())->add(new DateInterval('P1D')); $token = $tm->createToken($length, $expires, $userId); $validateUrl = 'https://example.com/reset?'.http_build_query(['id' => $token->getId(), 'token' => $token->getToken()]); //send reset token $tm = $container['token_manager']; $um = $container['user_manager']; $token = $tm->find($_GET['id']); if ($token->verify($_GET['token'])){ $user = $um->find($token->getContext()); $user->changePassword($_POST['newPassword']); } Seems like a reasonable public API so now create the interfaces needed for it. interface TokenManager { public function createToken($length, $expires, $context) : Token; public function find($tokenId) : ?Token; } interface Token { public function getId() : int; public function getContext(); public function getToken() : string; public function verify() : bool; } Finally create classes that implement those interfaces to provide your token service.
  16. The parameter you give to the WebSocket construct is just a standard URL using either the ws:// or wss:// scheme. The websocket protocol is built on top of http / https so it defaults to those same ports. ws:// uses HTTP and would default to 80, wss:// uses HTTPS and would default to 443. If you're server runs on an entirely separate port then you'd just specify that in the URL like shown. Yes, ratchet is an implementation of the server-side of the WebSocket protocol. Yes, it does use React. What you want to do is certainly possible. Your server can listen on however many ports it wants too, and having separate ports for the different client types is a good way to go. Setting up a simple server that can accept connections from both of your clients probably would not be that hard. Developing the process for how exactly to share the data and move things between clients is probably going to be where you'll have to spend the most time. Use as much already existing stuff as you can provided it does what you need (or can be easily modified to do so). It'll save you a lot of time and headache. Writing your own stuff generally isn't worth while unless your goal is specifically to learn about how to write said stuff. If you want to learn the depths of the websocket protocol and how it works then write your own server and client. If you just want to use it to get a job done, use pre-written stuff. Writing my own Websocket server (if your curious) back when I first started messing with this stuff was a pain, and what I ended up with would be pretty poor code compared to the stuff that exists today.
  17. What do you mean what happens in between? For the browser take a look at the Websocket API if you want to learn about how to deal with them. The basic code would look something like this: var socket = new WebSocket('ws://example.com:8000'); socket.onmessage = function(e){ /* e is a MessageEvent object (https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent) */ console.log(e.data); }; socket.send('Hello!'); If you want to connect from PHP over the websocket protocol to your server then you'd need to either find an implementation of the websocket protocol to use or create your own (which could be done using React's client sockets stuff). Also make sure your React server speaks the Websocket Protocol. WebSocket is a specific protocol with a defined format, not just a way to connect to any open socket server.
  18. You can tell ssh which ID to use by using the -i parameter. You'll also want to provide the host key through the known hosts file. So your command would be something like: ssh -i /path/to/id_rsa -o "UserKnownHostsFile /path/to/known_hosts" -p 2233 -f -L 3307:127.0.0.1:3306 acct@remote-server.com sleep 60 >> ./ssh.logfile 2>&1 The id_rsa file would contain your user private key and the known_hosts file would contain the server's name and public key, for example: remote-server.com ssh-rsa theserverpublickey Provided the remote server has the user's public key in it's authorized_hosts file then the connection should be successful. On a related note, why are you trying to establish the tunnel via a PHP script rather than just establishing one through a normal ssh session either when needed or persistently? When I need to open a tunnel for various reasons I ssh into where I need to create the tunnel and use a command like: ssh -L 3307:127.0.0.1:3306 -fNT -p 2233 acct@remote-server.com That establishes a persistent tunnel that just runs in the background. It'll remain open until either the process is killed or some network failure occurs.
  19. kicken

    linux command sed

    man sed So basically it modifies the given files to make a couple replacements.
  20. If you're after free then I have no idea what's good. If you don't mind paying a bit then I use PHPStorm and find it works wonderfully.
  21. If you're using a TCP stream for your connection and are comfortable assuming your clients/servers don't make mistakes then you'd be fine without any additional stuff probably. TCP will already ensure that all the data arrives in order and without accidental corruption so the only thing that might cause a problem would be a client sending bad data to begin with. So long as all your clients send packets in the form of "$length$data" and $length is always accurate you'll be fine. Closing the connection is just the easiest thing to do if your connection is somehow out of sync/receiving bad data. You could try and implement some kind of recovery that gets things back in sync but it's extra work. Just close the connection and let the client re-connect if they want. That'll reset things back to a known state with relatively little effort (you'll need reconnect capability anyway for network failures).
  22. If you're just after the numerical value of the first byte, then you can simply do: $byte = ord($buf[0]); echo $byte; Strings in PHP can be treated like an array and you can access the individual bytes directly by using the appropriate index. ord will give you the numeric value of a byte. There's no need for unpack at all in this code. If you want all the bytes you can do a for loop over the length of the string and run ord on each byte individually.
  23. I generally prefer to avoid changing the buffer unless I know I can extract a complete message. That way you don't have to keep track of state or partial information. For example: function parseBuffer(){ do { $checkAgain = false; $bufferLength = strlen($this->buffer); $length = $this->getLength(substr($this->buffer, 0, 4)); if ($bufferLength >= $length + 4){ $message = substr($this->buffer, 4, $length); $this->buffer = substr($this->buffer, $length+4); $this->emit('data', [$message]); $checkAgain = true; } } while ($checkAgain); } The buffer should always begin with a 4-byte length value assuming no transmission issues. Assume the first four bytes are the length and extract them then check if there's enough left in the buffer to satisfy the length. If not, do nothing and just return to let more data arrive. If so, extract the complete message, modify the buffer then check again for a second message. If you want to try and ensure that you don't try and parse bad data then you can do things like add checksums or require every packet to begin with a Magic number/code that you check against. If the magic ever doesn't match consider the connection failed and close it.
  24. So are you going to switch to delimiters or keep the length prefix? Your post suggests delimiters but your code is still using lengths. If you want to use delimiters, refer back to the JSONStream class and see how it handles parsing out individual items. Use strpos to search for the delimiter and then extract the message. If you want to continue with length processing then you could try looking at the Gearman code I wrote as an example. It doesn't use react but it will demonstrate parsing out a packet. Areas of interest may be Connection::readPacket and Packet::fromString public function readPacket(){ if (!$this->stream){ $this->connect(); } $header = $this->read(12); $size = substr($header, 8, 4); $size = Packet::fromBigEndian($size); $arguments = $size > 0?$this->read($size):''; return Packet::fromString($header . $arguments); } The gearman protocol specifies that each packet begins with a 4-byte magic code, 4-byte packet type and a 4-byte packet size (in network byte order). So first 12-bytes are read (4*3) then the last 4-byte group is extracted and turned into an integer to determine how much additional data is read. public static function fromString($data){ $magic = substr($data, 0, 4); $type = substr($data, 4, 4); $type = static::fromBigEndian($type); $size = substr($data, 8, 4); $size = static::fromBigEndian($size); $arguments = substr($data, 12, $size); $validSize = strlen($arguments) === $size; if (!$validSize){ throw new UnexpectedPacketException; } $arguments = explode(chr(0), $arguments); $packet = new static($magic, $type, $arguments); return $packet; } Once the packet is read in whole it's sent here and broken down into individual fields for easy consumption.
  25. You need to replace the bytes C2A0. Mysql doesn't understand html entities so using to represent a non-breaking space won't work. Try REPLACE(price, X'C2A0', '')
×
×
  • 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.