-
Posts
4,704 -
Joined
-
Last visited
-
Days Won
179
Everything posted by kicken
-
Slim is expecting your function to return an object implementing \Psr\Http\Message\ResponseInterface. In the case of a missing or invalid key though, you're just returning an array. What you need to do is use that array to create a response then return that response, such as via the $response->withJson method as you've done in other bits of code. $app->add(function(Request $request, Response $response, $next) { $key = $request->getHeaderLine('X-MyApp-Key'); if (empty($key)) { return $response->withJson(\MyApp\ErrorResponse::missingKey(), 401); } $account=$this->account; $account = $account->get($this->db,$key); if (!$account) { return $response->withJson(\MyApp\ErrorResponse::invalidKey(), 401); } $this->account=$account; return $next($request, $response); });
-
Is there a way to duplicate divs and increment them?
kicken replied to imgrooot's topic in PHP Coding Help
Use a loop and an array to store the results. $pages = []; for ($pageNumber=1; $pageNumber <= 100; $pageNumber++){ $pages[] = '<a href="?type='. $type_id .'&name='. $get_type_3_name_slug .'&page=' . $pageNumber . '">' . $pageNumber . '</a>'; } -
Manual page
-
Passing variables to anonymous function
kicken replied to NotionCommotion's topic in PHP Coding Help
You can't call the factory function directly like that because PHP will not understand the code properly. $this->random_func is interpreted as 'Get me the random_func' property but $this->random_func() is interpreted as 'Call the random_func method'. Since the class doesn't have a random_func method you get the error. What you need to do is first get the random_func property, then call it as a function. In PHP 7 you can use parenthesis to force the proper interpretation: ($this->random_func)(); For older PHP versions you have to either use a variable or call_user_func. $random_func = $this->random_func; $random_func(); //or call_user_func($this->random_func); -
Passing variables to anonymous function
kicken replied to NotionCommotion's topic in PHP Coding Help
The function you set on the container is passed an instance of the container as it's first parameter: Pimple Documentation If you want the global $config variable, you'd have to use it as you thought. In the case of your factory function service, you need to either pass a function that returns the factory function, or use the protect helper method. -
I wouldn't worry about just passing $this possibly providing access to too much. So long as your target class only deals with what it needs it doesn't really matter. Something you could do is create a function that returns your closure and does the parameter merging there. For example: function Controller($controller, $extra=[]){ return function(Request $request, Response $response){ $params = array_merge($extra, ['logger'=>$this->logger, 'db'=>$this->db, 'account'=>$this->account]); $controller = new $controller($params); return $response->withJson($controller->get()); }; } $app->get('/configure', Controller(\MyApp\Configure::class)); $app->get('/oneThatNeedsMore', Controller(\MyApp\Configure::class, ['extra'=>123])); Passing the class name would allow you to use different classes provided they all used the same structure. Alternatively you could pass an instance of a class that uses a specific interface and call a method to set the parameters / app object. interface ControllerInterface { public function setApplication($app); public function setParameters($params); public function get(Request $request); } abstract class Controller implements ControllerInterface { protected $app; protected $params = []; public function setApplication($app){ $this->app = $app; } public function setParams($params){ $this->params = $params; } } class Configure extends Controller(){ public function get(Request $request){ $logger = $this->app->logger; $db = $this->app->db; $account = $this->app->account; } } function Controller(ControllerInterface $controller, $extra=[]){ return function(Request $request, Response $response){ $controller->setApplication($this); $controller->setParams($extra); return $response->withJson($controller->get($request)); }; } $app->get('/configure', Controller(new Configure)); $app->get('/oneThatNeedsMore', Controller(new Configure, ['extra'=>123])); If you take some time to think about what you need to do and how to do it, you could come up with some better code based on your requirements. For example, maybe pass those extra parameters as constructor arguments instead. Maybe have the controller alias some useful services so you can just do $this->db instead of $this->app->db in your methods.
-
Your callback URL just needs to accept some POST data and store it somewhere. When Twilio calls it they will provide a bunch of details about the SMS as POST fields. You extract the data you want and do whatever you need to do with it. For example: <?php $from = $_POST['From']; $to = $_POST['To']; $message = $_POST['Body']; $handle = fopen('log.csv', 'a'); fputcsv($handle, [$from, $to, $message]); fclose($handle);
-
PHP Curl Check to see if Cookie exists from site you are visting
kicken replied to akphidelt2007's topic in Miscellaneous
Cookies are associated with the client (eg browser) being used to access the site. This is why for example if you go to ESPN and login with Firefox, you will not be logged in if you later visit with Chrome. Firefox and Chrome have separate cookie stores, as would cURL. It's not possible to use PHP (or cURL) to check if a user's browser has cookies for some third-party website. -
I generally try and stick the data attribute with the json onto whatever element the script will be affecting. If you need to just pass some data to the script itself (say configuration info or whatever), you can stick the data attribute onto the script tag. For example: <script data-types="{{ types|json_encode() }}"> (function(){ var types = $('script').last().data('types'); console.log(types); }()); </script>
-
If you want something generic, you could pass in a map of fields and error messages to a function that checks if they are empty or not and returns a list of errors. function validateRequired($fields, $data){ $Errors = []; foreach ($fields as $name=>$message){ if (!isset($data[$name]) || trim($data[$name]) == ''){ $Errors[] = $message; } } return $Errors; } $required = [ 'membership_type' => 'Type name is required' , 'membership_type_description' => 'Description is required' //, ... ]; $Errors = validateRequired($required, $_POST); if (count($Errors) == 0){ //Valid } If you need something a bit more tailored to a specific form, you can wrap that in it's own validate function which might call the required one as part of it's work. function validateMembershipType($data){ $required = [ 'membership_type' => 'Type name is required' , 'membership_type_description' => 'Description is required' //, ... ]; $Errors = validateRequired($required, $data); if (count($Errors) == 0){ if ($data['is_promo']){ $required = ['promo_start' => 'Promo start date is required']; $Errors = array_merge($Errors, validateRequired($required, $data)); if (!empty($data['promo_end'])){ $start = DateTime::createFromFormat('m/d/Y'); $end = DateTime::createFromFormat('m/d/Y'); if ($end <= $start){ $Errors[] = 'Promo end date must be after promo start date'; } } } } return $Errors; } That is more or less how I handle it in one of the older systems I maintain. In that system a typical CRUD style page looks like this (in pseudo-code): <?php $action = isset($_GET['action'])?$_GET['action']:'list'; $id = isset($_GET['id'])?$id:null; switch ($action) { case 'add': DoModify('add'); break; case 'edit': if (!$id){ throw new \RuntimeException('Missing id parameter'); } DoModify('edit', $id); break; case 'delete': if (!$id){ throw new \RuntimeException('Missing id parameter'); } DoDelete($id); break; default: DoList(); } function DoList(){ $items = loadAllFromDB(); Template::render('list.tpl', ['items' => $items]); } function DoModify($action, $id=null){ $Defaults = $Errors = []; if ($_SERVER['REQUEST_METHOD'] == 'POST'){ $Defaults = $data = $_POST; if (validatePostData($action, $data, $Errors)){ if ($id){ updateRecord($id, $data); } else { createRecord($data); } RedirectTo('?action=list'); return; } } else if ($id){ $Defaults = loadSingleFromDB($id); } Template::render('modify.tpl', [ 'id' => $id , 'action' => $action , 'Defaults' => $Defaults , 'Errors' => $Errors ]); } function DoDelete($id){ if ($_SERVER['REQUEST_METHOD'] == 'POST'){ //Create and run delete query } RedirectTo('?action=list'); } function validatePostData($type, &$data, &$Errors){ //validation and normalization here return count($Errors) == 0; } function updateRecord($id, $data){ //Create and run update query } function createRecord($data){ //Create and run insert query } I cheat a little bit and let the validation function also normalize the data (convert dates to DateTime objects, empty fields to null, etc). As such the data is pass-by-reference so that the normalization is reflected in the main code also. Errors are gathered in a pass-by-reference variable also so the function can return a simple true/false based on the overall validation.
-
The function still does not have access to the $row variable, you need to pass that to the function. You also have not addressed the issue of the field being reset to the database value when a user posts it as empty during editing, unless you just don't pass any original values into the function in that case. function extractData($fields, $source) { $data = []; foreach ($fields as $name) { if (!empty($source[$name])) { $data[$name] = $source[$name]; } } return $data; } $Defaults = []; if ($_SERVER['REQUEST_METHOD'] == 'POST'){ $fields = ['membership_category_id', ...]; $Defaults = extractData($fields, $_POST); } else if ($IsEditingMode){ $Defaults = loadRecordFromDatabase(); } Defaults will be an empty array initially. If data was posted, you extract the desired fields from $_POST ignoring empty fields, otherwise if the user is editing a record you load the defaults from the database. In the twig there's no need a condition, just output the value of the defaults array for that field.
-
Code is not working trying to login using SQL SERVER
kicken replied to TStyles's topic in PHP Coding Help
Did you match the dll versions properly (nts vs ts, x86 vs x64)? Did you ensure to check the System requirements? Namely: For version 4 you need Microsoft ODBC Driver 11 for SQL Server or Microsoft ODBC Driver 13 for SQL Server Lastly, I'd suggest using the PDO interface, not the sqlsrv_* functions. It's easier. //NULL username/password for Windows auth. $db = new PDO('sqlsrv:server=(local);Database=sample', null, null, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $stmt = $db->query('SELECT fname, lname FROM people'); foreach ($stmt as $row){ echo $row['fname'].' '.$row['lname'].'<br>'; } -
It's a bit pointless to do a try/catch just do die() with the exception message in the catch block. PHP's default behavior for an uncaught exception is to die with the exception message and a stack trace, so just use that. That's the point behind removing the try/catch.
-
I usually assign a Defaults variable to twig that contains all the default values for the form fields. Within the PHP code I will populate this either from the existing database record or $_POST depending on whether the request was a submission or not. if ($_SERVER['REQUEST_METHOD'] == 'POST'){ $Defaults = $_POST; //further processing } else { $Defaults = LoadRecordFromDB(); } $twig->render('template', ['Defaults' => $Defaults]); <input type="text" name="membership_type_description" value="{{ Defaults.membership_type_description }}">
-
In your PHP script you'd run the query and generate an array with the data you need in as simple of a form as possible. For example an options array with value, label, and selected keys. <?php $sql = "SELECT person_id, first_name FROM people"; $stmt = $pdo->prepare($sql); $stmt->execute(); $options = []; foreach ($stmt as $row){ $options[] = [ 'selected' => isset($person_id)) && $person_id == $row['person_id'] , 'value' => $row['person_id'] , 'label' => $row['first_name'] ]; } //Pass $options to the template In your template you loop over that array and generate the select options based on the array data. <select id="person_id" name="person_id" class="form-control"> <option value="">Select Person</option> {% for opt in options %} <option value="{{ opt.value }}" {{ opt.selected?'selected="selected"':'' }}>{{ opt.label }}</option> {% endfor %} </select> If you have a particular bit of HTML you need to use site-wide that needs to be generated you could look into creating a twig function that will render the necessary HTML, then just call it from your template (like how dump() works).
-
Using for...in with an array (or array-like object) is not preferred. There is no guarantee over the order items will be iterated in and in the case of an array-like object it may include other properties you do not want. Use a regular for loop with a numeric index. for(var i=0; i<_form.elements.length; i++){ console.log(_form.elements[i].type + ' : ' + _form.elements[i].name); }
-
It's called temporary for a reason. CREATE TABLE manual page
-
You cannot use the date/strtotime functions to deal with a duration. They are for dealing with an absolute time. What you've done might happen to work for a period less than 24-hours but will fail for more than that. Crossing the 24-hour mark will result in an increase to the date and reset the hours back to 0. Probably the simplest thing to do would be to have your query just return a total number of seconds rather than a formatted duration. Then you can write a function to take those seconds and format it for display. function formatDuration($sec){ $h = floor($sec/(60*60)); $sec -= $h*(60*60); $m = floor($sec/60); $sec -= $m*60; return sprintf("%02d:%02d:%02d", $h, $m, $sec); } That would give you a simple HH:mm:ss display for your durations. If you do a little searching you can find all sorts of duration formatting functions. Then in your code you change the query to return seconds and use normal math to sum them and the function to display the result. $query = " SELECT hours_id, member_id, member_name, team, time_in, time_out, TIME_TO_SEC(TIMEDIFF(time_out, time_in)) AS totalhours FROM hours where time_in LIKE '%".$chk."%' and member_id = '".$usr."' "; $total_time = 0; while($row = mysql_fetch_assoc($result)){ $total_time += $row['totalhours']; //... echo"<td><font color='white'>" .formatDuration($row['totalhours'])." Hrs</font></td>"; }
-
There are lots of pre-written libraries out there to handle sorting lists using Javascript. You could grab one of those to implement the sorting then tie it into your PHP either with a form submit or a Ajax call, whichever you find easiest. For example I've used Jquery UI's Sortable widget a few times in the past without much hassle. User's can drag-n-drop sort the elements in the DOM and you listen for the update event to know when the order has changed. When the order has changed you can inspect the dom to determine the new order then save that state into an input for a later form post or you could post it immediately with a ajax call. Example
-
I would recommend using one table with two columns. There's no good way to join your two tables in order to get the duration between the time-in and time-out records. A single table means you don't have to duplicate the other fields either. CREATE TABLE timelog ( id int NOT NULL AUTO_INCREMENT PRIMARY KEY, member_id int NOT NULL, time_in DATETIME NOT NULL, time_out DATETIME NULL ); When someone wants to clock in, you insert a new row with the time_in value set to the current time and time_out NULL. INSERT INTO timelog (member_id, time_in) values (1, UTC_TIMESTAMP()) When they clock out, you'd update the row's time_out value with the current timestamp UPDATE timelog SET time_out=UTC_TIMESTAMP() WHERE member_id=1 AND time_out IS NULL You'll need to check when doing a clock-in that there is no existing record with a NULL time_out column. In other words, prevent someone from clocking in twice without clocking out first. Then to get your monthly hours tally you'd use a query like I showed above. SELECT member_id, SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(time_out, time_in)))) duration FROM timelog WHERE time_in >= '2016-06-01 00:00:00' AND time_in < '2016-07-01 00:00:00' GROUP BY member_id Fiddle
-
There are three ways you could handle this: 1) Count the entire shift as part of the month it started in 2) Count the entire shift as part of the month it ended in 3) Try and split the time. This is ultimately a business decision. You need to ask your client (or yourself) which method you want to use and then code for that method. #1 is probably the most common and what most people would expect. Its also relatively easy to do. You'd just query the database for shifts starting within the month then sum the difference between their in and out times. SELECT empid, time_in, time_out, TIMEDIFF(time_out, time_in) duration FROM timelog WHERE time_in >= '2016-07-01 00:00:00' time_in < '2016-08-01 00:00:00'
-
If you're doing a normal submit then the page would be reloaded and start at the top automatically. Are you using Ajax or something to submit the form or some other method that prevents a page reload?
-
I've never dealt with that situation, but if I were to come across it I think I'd be inclined to either negotiate an increased rate, or negotiate a licensing deal rather than a full copyright transfer. Since you'd have no rights to the code after signing such an agreement I think additional compensation in the form of a higher rate would be reasonable. You'd have to decide how much of a rate increase that loss is worth and negotiate with them. You'd also want to consider if you want any increased compensation for work already done or just from this point forward. Alternatively you could try and retain your ownership of the code and just license it to them. The terms of the license would permit them to sub-license it to other companies in exchange for some sort of fee to you such as a yearly payment or a per-sub-licence payment. This might be more hassle than it'd be worth though unless you have some specific plan to re-use or re-sell the code.
-
Neither, it would create: <div><span>bar</span></div> (->value should be ->nodeValue). The second appendChild essentially does nothing. $span can only exist at one place in the document. The first appendChild would place it as the first child of $div. The second appendChild would move it to the "second child of div" position, but that would remove it as the first-child meaning it's still just the first-child in the end.
-
Fatal error: Using $this when not in object context Error message
kicken replied to lovephp's topic in PHP Coding Help
Wherever you got that code from, it expects to be part of a class which has a seems_utf8 function in it. You need to either get the entire class and use it or modify the code to not use $this. If you have a seems_utf8 function, just change the call to remove $this-> and it may work (depending on what the seems_utf8 function looks like). If you don't have that function you'll need to get it. Since it seems like what you may be trying to do is convert the title to ascii for use as a URL slug, you could also just try removing all that and using iconv to convert from the input charset to ascii. For example: <?php function create_slug($title){ //Convert to ascii $slug = iconv('windows-1252', 'ascii//TRANSLIT//IGNORE', $title); //Lowercase and limit length $slug = strtolower(substr($slug, 0, 90)); //Replace whitespace with a - $slug = preg_replace('/\s+/', '-', $slug); //Remove non a-z, 0-9, - characters. $slug = preg_replace('/[^a-z0-9-]+/', '', $slug); //Combine multiple - into a single - $slug = preg_replace('/-+/', '-', $slug); //Strip leading or trailing - $slug = trim($slug, '-'); return $slug; } You may need to adjust your in charset.