I have an array of people that is registered as online in a html file. I am using this so that each can have an image assigned to them. But when checking to see if using name is already in use the in_array function return false and allow the script to continue.
$user = "< img src='default.jpg' />John";
$explode = array("<img src='tress.jpg' />John");
if(in_array($user, $explode))
{
//show login script if user exists
}
else
{
//continue to script
}
Now the reason this is not working is because the john in the array is not identical to the john in $user. Is there anyway of checking that the name exists in the array? When responding please explain.
Instead of asking, "How do I solve this problem?", you need to start with, "Why am I having this problem?"
$user = "< img src='default.jpg' />John";
Is < img src='default.jpg' />John a user name? Why are you using it as one? I'm guessing there's some clever thought behind this like "Well, I always display a user's image with their name, so I'll just make the image part of their name. This is going to cause far more problems than it solves. This comes back to a big concept in computer science called separation of concerns. An image is not logically a part of a user name, so don't store it as one. If you always display them together, you can use functions to display a user's information in a standard way without making the image part of the user name.
So first off, remove the image from the name. There are several ways to store this separately.
I would suggest using a class:
class User {
public $name;
public $imageSource;
// The following functions are optional, but show how a class
// can be useful.
/**
* Create a user with the given name and URL to their image
*/
function __construct($name, $imageSource) {
$this->name = $name;
$this->imageSource = $imageSource;
}
/**
* Gets the HTML to display a user's image
*/
function image() {
return "<img src='". $this->imageSource ."' />";
}
/**
* Gets HTML to display to identify a user (including image)
*/
function display() {
return $this->image() . $this->name;
}
}
$user = new User("john", "default.jpg");
// or without the constructor defined
//$user = new User();
//$user->name = "john";
//$user->imageSource = "default.jpg";
echo $user->display();
You can use an "array" if you want to be a little lazier, but I don't recommend it in the general case, since you lose the cool features of classes (like those functions):
$user = array(
name => "john",
image => "<img src='default.jpg' />";
);
echo $user["image"] . $user["name"];
In your database (if you're using one), make them separate columns and then use one of the above data structures.
Now that you have this, it's easy to see if a user name is in a given list using a foreach loop:
function userNameInList($user, $users) {
for($users as $current) {
if($user->name == $current) {
return true;
}
}
return false;
}
$newUser = new User("John", "john.jpg");
$currentUsers = array("John", "Mary", "Bob");
if(userNameInList($newUser, $currentUsers) {
echo "Sorry, user name " . $newUser->name . " is already in use!";
}
If you're new to PHP, the normal for loop may be easier to understand:
function userNameInList($user, $users) {
for($i = 0; $i < count($users); ++i) {
$current = $users[$i];
if($user->name == $current) {
return true;
}
}
return false;
}
Let me know if any of this doesn't run, I don't write PHP very often anymore..
Related
first question here, because i'm stuck since this morning and i don't find a single way to fix my problem.
I'm trying to show every images listed in my DB (DB contains img name, img are stored in local files, each has been send in the same time via an input page).
The current code do not send any errors between thoses parts :
public function findall()
{
require_once ('Classes/ClasseDB.php');
$pdo = Database::connect();
$req = "SELECT IDphoto, nomImage, testCom FROM test";
$stmt = $pdo->query($req);
$CollectionPhotos = array();
while ($ligne = $stmt->fetch())
{
$LaPhoto = new ClasseTest($ligne["testCom"]);
array_push($CollectionPhotos, $LaPhoto);
}
return $CollectionPhotos;
}
public function get_nomImage()
{
return $this->nomImage;
}
And
Image List :
<?php
echo "test1 ";
require_once "Classes/ClasseTest.php";
$laPhoto = new ClasseTest;
$CollectionPhotos = $laPhoto -> findall();
$i = 0;
echo "test2 ";
while ($i < count($CollectionPhotos)){
// here is where it's broken ↓
echo $CollectionPhotos[$i]->get_nomImage(); //don't work :'(
//html <img __ > is removed in order to simplify
echo 'test3 '; //shows every items
$i++;
}
echo "test4 ";
?>
ClasseDB code here as asked :
<?php
class Database {
public static $conn = null;
public static function connect() {
if ( null == self::$conn ) {
try {
self::$conn = new PDO('mysql:host=localhost;dbname=myDB', 'root', '');
self::$conn->query("SET NAMES 'utf8'");
self::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
die($e->getMessage());
}
}
return self::$conn;
}
}
?>
Each tests are shown, and 'test3' appears 10 times, so i know my loop repeats enough times.
Nb : this is like what we did in class...
So what is wronnnng, is that a newbie mistake, a misspelling or a bug (my pc has done everything to me so that's also possible) ?
In your SQL query, you select three columns:
SELECT IDphoto, nomImage, testCom FROM test
However, only one of these is actually referenced in your PHP code:
$LaPhoto = new ClasseTest($ligne["testCom"]);
You haven't shown the constructor of ClasseTest, so it's not clear where testCom is stored (if anywhere), but from its name, I suspect it is not in the nomImage property, which is what you later try to retrieve:
public function get_nomImage()
{
return $this->nomImage;
}
That property is presumably supposed to come from the nomImage column in the database, which you're not storing anywhere.
You can help yourself a lot by naming things more carefully and thinking about responsibilities. If you want an object representing a photo, the logical name for it would be Photo, and you would pass all the columns you've selected to its constructor:
$LaPhoto = new Photo($ligne["IDphoto"], $ligne["nomImage"], $ligne["testCom"]);
Your findAll method doesn't belong to a single photo, so you can either put it on a different class, like ChercheurPhoto:
$leChercheurPhoto = new ChercheurPhoto;
$CollectionPhotos = $leChercheurPhoto->findall();
Or, you can use a static method, which is a method on the class, not a particular instance of the class:
$CollectionPhotos = Photo::findall();
I am currently writing an adress book and using a framework (CakePHP) an MVC for the first time. Unfortunately I have some trouble.
I want to realize the following:
In case the URL is
/contacts/view/
I want to show all contacts in a list. In case there is an id given after /view/, e.g.
/contacts/view/1
I just want to display the contact with the id 1. (complete different view/design than in the first case)
My ContactsController.php is the following
public function view($id = null){
if(!$this->id){
/*
* Show all users
*/
$this->set('mode', 'all');
$this->set('contacts', $this->Contact->find('all'));
} else {
/*
* Show a specific user
*/
$this->set('mode','single');
if(!$this->Contact->findByid($id)){
throw new NotFoundException(__('User not found'));
} else {
$this->set('contact', $this->Contact->findByid($id));
};
}
}
But "$this->mode" is always set as "all". How can I check whether the id is set or not?
I really want to avoid "ugly" URL-schemes like ?id=1
Thanks in advance!
Your code is only meeting the if part and its not going to else part. Use (!$id)..
$_GET data is retrieved through the URL. In CakePHP this means it's accessed through that method's parameters.
I'm arbitrarily picking names, so please follow! If you're in the guests controller and posting to the register method you'd access it like this
function register($param1, $param2, $param3){
}
Each of these params is the GET data, so the URL would look something like
www.example.com/guests/param1/param2/param3
So now for your question How can I check whether the id is set or not?
There are a couple of possibilities. If you want to check if the ID exists, you can do something like
$this->Model->set = $param1
if (!$this->Model->exists()) {
throw new NotFoundException(__('Invalid user'));
}
else{
//conduct search
}
Or you can just search based on whether or not the parameter is set
if(isset($param1)){ //param1 is set
$search = $this->Model->find('all','conditions=>array('id' => $param1)));
}
else{
$search = $this->Model->find('all');
}
You should only change the conditions not the whole block of code like
public function view($id = null){
$conditions = array();
$mode = 'all';
if($id){
$conditions['Contact.id'] = $id;
$mode = 'single';
}
$contacts = $this->Contact->find('all', array('conditions' => $conditions));
$this->set(compact('contacts', 'mode'));
}
I am adapting StationWagon (FuelPHP app) and so far it's working really well.
I have adapted it (with some help) to allow multiple images to be uploaded to the server. This is also working great.
However, I am thinking it would make more sense if I had 2 Tables: 1) Articles and 2) ArticleImages. I would use a Foreign Key to associate the Images with the Article. So when publishing an article it would add the article data to 'Articles' table and move each image to a new row in 'ArticleImages'.
So ultimately my 'ArticleImages' table could be:
ID | ImageURL | ArticleID
Portion of my 'articles.php' controller:
<?php
public function action_add()
{
$val = Model_Article::validate('add_article'); //<-- maybe its just me but i never saw any similar to this in fuelphp sorry about this if im wrong
// if your form validation is okay than continue with everyhing else
if ($val->run())
{
$article = Model_Article::forge();
// Custom configuration for this upload
$config = array(
'path' => DOCROOT.DS.'images',
'randomize' => true,
'ext_whitelist' => array('img', 'jpg', 'jpeg', 'gif', 'png'),
);
Upload::process($config);
// if a valid file is passed than the function will save, or if its not empty
if (Upload::is_valid())
{
// save them according to the config
Upload::save();
//if you want to save to tha database lets grab the file name
$value = Upload::get_files();
foreach($value as $files) {
print_r($files);
}
$article->filename = $value[0]['saved_as'];
}
$status = (Input::post('save_draft') ? 0 : 1);
if ( ! $val->input('category_id'))
{
$category_id = null;
}
else
{
$category_id = $val->validated('category_id');
}
$article->user_id = $this->user_id;
$article->category_id = $category_id;
$article->title = $val->validated('title');
$article->body = $val->validated('body');
$article->published = $status;
if ($article->save())
{
Session::set_flash('success', 'Article successfully added.');
}
else
{
Session::set_flash('error', 'Something went wrong, '.
'please try again!');
}
Response::redirect('articles/add');
}
$this->template->title = 'Add Article';
$this->template->content = View::forge('articles/add')
->set('categories', Model_Category::find('all'), false)
->set('val', Validation::instance('add_article'), false);
}
/* End of file articles.php */
You are trying to make a relation between Articles and ArticleImages. An ArticleImage belongs to an Article, while an Article has many ArticleImages. FuelPHP has functionality built in for what you are trying to achieve. Have a look at the FuelPHP docs on its Object Relational Mapper, especially the Belongs To and Has Many relations.
So when i made the code for you back a few days a go you only requested, one file input.
And no offense but you are doing it all wrong...
foreach($value as $files) {
print_r($files);
}
$article->filename = $value[0]['saved_as'];
should be
foreach($value as $files) {
$articleimg = Model_Articleimages::forge();
$articleimg->image_row_name = $files['saved_as']
}
To get you to understand
what you did here, $value = Upload::get_files(); yes this gets all the elements but since you need to loop trouh the elements you dont need it
Second
this $value[0]['saved_as'] only grabs the first image name, just the first one, and since you are in a loop now you need to refer to the $files variable as i shown you in the above example, just an example
I know this sounds very much like "Is there a PHP framework that does my entire job for me?" But bear with me.
Say I want to create a signup form for a camp, and I have a simple data structure in mind --
Person
First name
Last name
Address
Address
Line 1
Line 2
Suburb
Town
etc
Things I have seen that do part but not all of what I want:
PHP form libraries like jFormer and ValidForm (not to mention all the big frameworks): these things let you define the form you want to make using a little bit of PHP -- so you'd say "add text field, add textarea", etc -- but they don't let the user edit the form data structure, nor do they automatically save into a data structure. They're more useful for developers.
Front-end form creators like foxyform, jotform: they let the user edit the form but the backend needs to be done in some other way, and it's not linked up.
Then there's Wordpress Pods CMS, which is almost exactly what I want -- but without the wordpress part.
Ideally, I would like one of two things:
1) A microframework where you define your data schema in some reasonably simple way, like say Json or Yaml -- your basic
Person
First name: Text
Last name: Text
Address: has_one Address
Address
... and so on
And it would take that and create the form you needed and maybe even create the database schema and so forth. You could then get hold of the data objects to iterate over in your code elsewhere (I'm not crazy enough to try and automate that as well... Or maybe I am, but certainly it feels outside the scope of this particular encapsulation).
OR
2) The above, plus a little editor for editing the data schema.
Create data type:
Name: [Person]
Fields:
First name: [Text field]
[+ Add field]
I have had a good look around and haven't found anything that's small and standalone and does just this. Pods CMS is almost exactly what I want, but smaller and cleaner and not tied to Wordpress.
Does such a thing exist? If not -- and I'm straying onto opinion here but I'll take a chance -- does it seem like such a thing should exist? Wouldn't it be nice to just be able to drop such a thing into any application, and either write the schema yourself or allow the user to edit it? It doesn't seem so very difficult, and it would be usable in so many contexts.
I am not quite sure such a detail of personalization exists but let's give it a try:
First you should create your classes:
class Person{
private $first_name;
private $last_name;
private $adress;
public function __construct($data=array(), adress $adress=null){
foreach ($data as $cle => $valeur)
$this->$cle=$valeur;
$this->adress=$adress;
}
public function __get($property){
return $this->$property;
}
public function __set($property,$value)
{
$this->$property=$value;
}
public function all_object_properties() {
return get_object_vars($this);
}
public function all_class_properties(){
return get_class_vars(__CLASS__);
}
}
class Adress{
private $id;
private $line_1;
private $line_2;
private $suburb;
public function __construct($data=array()){
foreach ($data as $cle => $valeur)
$this->$cle=$valeur;
}
public function __get($property){
return $this->$property;
}
public function __set($property,$value)
{
$this->$property=$value;
}
public function all_object_properties() {
return get_object_vars($this);
}
public function all_class_properties(){
return get_class_vars(__CLASS__);
}
public function fill($id){
$connexion=db_connect();
$req=$connexion->prepare("SELECT * FROM adresses WHERE id=:id");
$req->execute(array('id'=>$id));
while ($row = $req->fetch(PDO::FETCH_ASSOC)){
foreach ($row as $cle => $valeur)
$this->$cle=$valeur;
}
return $this;
}
public function save(){
$connexion=db_connect();
$sql1="INSERT INTO adresses (";
$sql2=" VALUES (";
$vars=$this->all_properties();
foreach($vars as $var=>$value){
$sql1.=$var.", ";
$sql2.=":".$var.", ";
}
$sql1=substr($sql1,0,-2).")";
$sql2=substr($sql2,0,-2).")";
$sql=$sql1.$sql2;
$query=$connexion->prepare($sql);
$query->execute($vars);
if($query){
$this->id=$connexion->lastInsertId();
return true;
}else{
return false;
}
}
public function update(){
$connexion=db_connect();
$sql1="UPDATE adresses SET ";
$vars=$this->all_properties();
foreach($vars as $var=>$value){
$sql1.=$var."=".":".$var.", ";
}
$sql1=substr($sql1,0,-2)." WHERE id=:id";
$query=$connexion->prepare($sql1);
$query->execute($vars);
if($query){
return true;
}else{
return false;
}
}
}
Then you want the ability to create a form based on a file like JSON or even XML:
<forms>
<form>
<host>name_of_my_page_where_my_form_is_displayed.php</host>
<method>post</method>
<target>#</method>
<input>
<type>text</type>
<name>first_name</type>
<class>Person</class>
</input>
<input>
<type>text</type>
<name>last_name</type>
<class>Person</class>
</input>
<input>
<type>text</type>
<name>line_1</type>
<class>Adress</class>
</input>
<input>
<type>text</type>
<name>suburb</type>
<class>Adress</class>
</input>
</form>
</forms>
Here you need a function to parse and create the form:
function display_form($xml_file,$page_to_display){
$content=null;
$values=array();
$dom = new DOMDocument;
$dom->load($xml_file);
$forms=$dom->getElementsByTagName("form");
foreach($forms as $form){
$urls = $form->getElementsByTagName( "host" );
$url = $urls->item(0)->nodeValue;
if($url==htmlspecialchars($page_to_display)){
$tp_method = $form->getElementsByTagName( "method" );
$method = $tp_method->item(0)->nodeValue;
$tp_target = $form->getElementsByTagName( "target" );
$target = $tp_target->item(0)->nodeValue;
$content="<form action=".$target." method=".$method."><br/>";
$inputs=$dom->getElementsByTagName("input");
foreach($inputs as $input){
$tp = $form->getElementsByTagName( "type" );
$type = $tp->item(0)->nodeValue;
$tp = $form->getElementsByTagName( "name" );
$name = $tp->item(0)->nodeValue;
$tp = $form->getElementsByTagName( "class" );
$class = $tp->item(0)->nodeValue;
$content.="<input type=".$type." name=".$name."/><br/>";
$values[]=array("class"=>$class,"name"=>$name);
}
$content.="<input type='submit' value='Submit'/>";
}
}
return array("content"=>$content,"values"=>$values);
}
Finally in your page where the form is displayed:
<?php
$array=display_form("forms.xml",$_SERVER['REQUEST_URI']);
$content=$array['content'];
$values=$array['values'];
$classes=array();
$names=array();
foreach($values as $tab){
$class=$tab['class'];
$name=$tab['name'];
$classes[]=(!in_array($class,$classes)) ? $class : null;
$names[]=$name;
${$class}[]=$name;
}
$form_submitted=true;
foreach($names as $name){
if(!isset($_POST[$name]))
$form_submitted=false;
}
if($form_submitted){
foreach($classes as $name_class){
$var= new $name_class;
foreach(${$name_class} as $value){
$var->__set($value,$_POST[$value]);
}
$var->save();
}
}
echo $content;
In addition, you may want to create a function to fill your xml.
In each classes you can use functions fill() to retrieve data for an object in the database based on their ID, save() to create a new insert in the database, or update() to update an already existent row based on the ID.
There is a lot of improvement which can be done, but the general idea is here.
Feel free to improve it and make yours!
I have users' table users, where I store information like post_count and so on. I want to have ~50 badges and it is going to be even more than that in future.
So, I want to have a page where member of website could go and take the badge, not automatically give him it like in SO. And after he clicks a button called smth like "Take 'Made 10 posts' badge" the system checks if he has posted 10 posts and doesn't have this badge already, and if it's ok, give him the badge and insert into the new table the badge's id and user_id that member couldn't take it twice.
But I have so many badges, so do I really need to put so many if's to check for all badges? What would be your suggestion on this? How can I make it more optimal if it's even possible?
Thank you.
optimal would be IMHO the the following:
have an object for the user with functions that return user specific attributes/metrics that you initialise with the proper user id (you probably wanna make this a singleton/static for some elements...):
<?
class User {
public function initUser($id) {
/* initialise the user. maby load all metrics now, or if they
are intensive on demand when the functions are called.
you can cache them in a class variable*/
}
public function getPostCount() {
// return number of posts
}
public function getRegisterDate() {
// return register date
}
public function getNumberOfLogins() {
// return the number of logins the user has made over time
}
}
?>
have a badge object that is initialised with an id/key and loads dependencies from your database:
<?
class Badge {
protected $dependencies = array();
public function initBadge($id) {
$this->loadDependencies($id);
}
protected function loadDependencies() {
// load data from mysql and store it into dependencies like so:
$dependencies = array(array(
'value' => 300,
'type' => 'PostCount',
'compare => 'greater',
),...);
$this->dependencies = $dependencies;
}
public function getDependencies() {
return $this->dependencies;
}
}
?>
then you could have a class that controls the awarding of batches (you can also do it inside user...)
and checks dependencies and prints failed dependencies etc...
<?
class BadgeAwarder {
protected $badge = null;
protected $user = null;
public function awardBadge($userid,$badge) {
if(is_null($this->badge)) {
$this->badge = new Badge; // or something else for strange freaky badges, passed by $badge
}
$this->badge->initBadge($badge);
if(is_null($this->user)) {
$this->user = new User;
$this->user->initUser($userid);
}
$allowed = $this->checkDependencies();
if($allowed === true) {
// grant badge, print congratulations
} else if(is_array($failed)) {
// sorry, you failed tu full fill thef ollowing dependencies: print_r($failed);
} else {
echo "error?";
}
}
protected function checkDependencies() {
$failed = array();
foreach($this->badge->getDependencies() as $depdency) {
$value = call_user_func(array($this->badge, 'get'.$depdency['type']));
if(!$this->compare($value,$depdency['value'],$dependency['compare'])) {
$failed[] = $dependency;
}
}
if(count($failed) > 0) {
return $failed;
} else {
return true;
}
}
protected function compare($val1,$val2,$operator) {
if($operator == 'greater') {
return ($val1 > $val2);
}
}
}
?>
you can extend to this class if you have very custom batches that require weird calculations.
hope i brought you on the right track.
untested andp robably full of syntax errors.
welcome to the world of object oriented programming. still wanna do this?
Maybe throw the information into a table and check against that? If it's based on the number of posts, have fields for badge_name and post_count and check that way?