PHP - Use a function to create a string help

DritzDritz Registered User regular
edited December 2006 in Help / Advice Forum
Alright so I've been using php for years but it's always been as a newbie and I've never really progressed beyond the basics. About the only thing I know about php inside and out is DOM functions which doesn't exactly help me here.

Anyways I'm trying to construct a string using a function and am meeting with limited success. Here's the basics:
function prepare_tags($tag,$is_text,$content,$has_attributes,$attributes) {

	// Quick and easy if is_text is true otherwise find attributes
	
	if ($is_text) {
		echo $content;
	}
	else {
	
		// Start the tag
	
		echo '<'. $tag;
		
		// Check for attributes
		
		if ($has_attributes) {
			foreach ($attributes as $attribute) {
				echo ' '. $attribute->name .'="'. $attribute->value .'"';
			}
		}
		
		// End the tag
		
		echo '>'. $content .'</'. $tag .'>';
		
	}
}

When I call the function like this:
$clean_tags = prepare_tags($tag,$is_text,$content,$has_attributes,$attributes);

It simply prints out the string instead of allowing me to take the $clean_tags variable and apply it somewere else. I've gone through the php manual quite extensively and have searched google but I'm a little tired after writing this script.

I'm writing something to create an rss feed by the way.

There I was, 3DS: 2621-2671-9899 (Ekera), Wii U: LostCrescendo
Dritz on

Posts

  • JaninJanin Registered User
    edited December 2006
    You need to go pick up a book on what PHP and HTML are, before whatever you're doing goes any further.

    First, the only DOM methods PHP would have would be to manipulate XML. If you knew those, you would know what you're doing is very wrong. This leads me to suspect when you speak of DOM methods, you are talking about Javascript.

    Second, it looks like you're just trying to escape some text. I'm not very familiar with PHP, but it must have a function for doing that built into the base library.

    Third, confusion over why it's printing out the value. The function you gave uses echo, which prints directly to the output. You need to learn about what a function is, and how to use a return value. You could try some programming tutorials, or could buy one of those "* for dummies" books.

    Janin on
    [SIGPIC][/SIGPIC]
  • japanjapan Registered User regular
    edited December 2006
    I'm confused as well. It looks like you're passing a series of strings into a function, then echoing them to the output (i.e. printing them to the page) instead of concatenating and storing them. Then you don't specify any return value.

    Somewhere inside your function it should say:

    return $outputstring;

    but it doesn't, so your function doesn't pass back any variables.

    Just so I know what you are trying to do, this function should take an XHTML tag and it's attributes as arguments, construct the complete tag as escaped XHTML (that is to say, you want the tag to be printed to the screen, not part of the page) contained within a string, then pass that string back to the rest of the script. Correct?

    japan on
  • DritzDritz Registered User regular
    edited December 2006
    The whole thing is a little tricky and that was just snippets, I figured that I didn't need to post the whole thing. Japan I think has got the intended idea of what I'm trying to do. This is a personal project of mine to create a feed for one of my favourite sites so I don't always have the luxury of working with XHTML, so there a few things I'm doing.

    *Note there are a few things wrong with this script aside from what I'm asking about here. I haven't completely finished it yet but for the moment I want to focus on this particular problem.
    <?php
    
    // Page location and save file
    
    $site = 'http://www.x.com/index.shtml';
    $save_file = 'x.xml';
    
    // Create the RSS document
    
    $rss_dom = new DOMDocument('1.0', 'iso-8859-1');
    
    $rss_root = $rss_dom->createElement('rss');
    $rss_dom->appendChild($rss_root);
    $rss_root->setAttribute('version', '2.0');
    
    // Add the channel
    
    $rss_channel = $rss_dom->createElement('channel');
    $rss_root->appendChild($rss_channel);
    
    // Site Info
    
    $title = 'Site';
    $link = 'http://www.x.com';
    $description = 'blee;
    
    // Create site info nodes
    
    $rss_title = $rss_dom->createElement('title', $title);
    $rss_link = $rss_dom->createElement('link', $link);
    $rss_description = $rss_dom->createElement('description', $description);
    
    // Append site info nodes
    
    $rss_channel->appendChild($rss_title);
    $rss_channel->appendChild($rss_link);
    $rss_channel->appendChild($rss_description);
    
    // Initiate connection with site and save copy
    
    $ch = curl_init($site);
    $fp = @fopen($save_file, "w");
    curl_setopt($ch, CURLOPT_FILE, $fp);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
    
    // Empty save file into a string
    
    $na = file_get_contents($save_file);
    
    // Define forbidden tags and replace
    
    $forbidden = array(
    	'@<script[^>]*?>.*?</script>@si',
    	'@<style[^>]*?>.*?</style>@siU',
    	'@<[\/\!]*?font[^>]*?>@si',
    	'@<[\/\!]*?tr[^>]*?>@si',
    	'@<[\/\!]*?td[^>]*?>@si',
    	'@<map[^>]*?>.*?</map>@si',
    	'@<form[^>]*?>.*?</form>@si',
    	'@@si',
    	'@<meta[^>]*?>@si',
    );
    
    $replacement = '';
    
    $na = preg_replace($forbidden, $replacement, $na);
    
    // Close common tags
    
    $close_tags = array(
    	'img',
    	'br',
    );
    
    foreach ($close_tags as $close_tag) {
    	$invalid_tag = '@<[\/\!]*?'. $close_tag .'[^>]*?>@si';
    	preg_match_all($invalid_tag, $na, $all_invalid, PREG_PATTERN_ORDER);
    	foreach ($all_invalid[0] as $invalid_case) {
    		$valid_tag = str_replace('>', ' />', $invalid_case);
    		$na = str_replace($invalid_case, $valid_tag, $na);
    	}
    }
    
    // Declare XML and save
    
    $xml_dec = '<?xml version="1.0" encoding="UTF-8"?>';
    
    $xml_file = $xml_dec ."\n". $na;
    
    file_put_contents($save_file, $xml_file);
    
    // Make a function to convert tags
    
    function prepare_tags($tag,$is_text,$content,$has_attributes,$attributes) {
    
    	// Quick and easy if is_text is true otherwise find attributes
    	
    	if ($is_text) {
    		echo $content;
    	}
    	else {
    	
    		// Start the tag
    	
    		echo '&lt;'. $tag;
    		
    		// Check for attributes
    		
    		if ($has_attributes) {
    			foreach ($attributes as $attribute) {
    				echo ' '. $attribute->name .'="'. $attribute->value .'"';
    			}
    		}
    		
    		// End the tag
    		
    		echo '&gt;'. $content .'&lt;/'. $tag .'&gt;';
    		
    	}
    }
    
    // Make a function to combine fragments
    
    function combine_frags($fragments) {
    
    	// Go through the array
    	
    	foreach ($fragments as $fragment) {
    		echo $fragment;
    	}
    }
    
    // Open duplicate file
    
    $x_dom = new DOMDocument();
    $x_dom->loadHTMLFile($save_file);
    
    // Try and find headlines
    
    $x_links = $x_dom->getElementsByTagName('a');
    
    foreach ($nexusatlas_links as $item_link) {
    	if ($item_link->hasAttribute('href')) {
    		$item_link_target = $item_link->getAttribute('href');
    		$item_link_format = '/newsitem/i';
    
    		if (preg_match($item_link_format, $item_link_target)) {
    			// Create a new item
    
    			$rss_item = $rss_dom->createElement('item');
    			$rss_channel->appendChild($rss_item);
    		
    			// Add title and link
    
    			$item_title = $item_link->nodeValue;
    			$rss_item_title = $rss_dom->createElement('title', $item_title);
    			$rss_item_link = $rss_dom->createElement('link', $item_link_target);
    		
    			$rss_item->appendChild($rss_item_title);
    			$rss_item->appendChild($rss_item_link);
    		
    			// Find where the link points to and search it's siblings
    			
    			$item_destination_url = explode('#', $item_link_target);
    			
    			foreach ($nexusatlas_links as $item_link) {
    				if ($item_link->hasAttribute('name')) {
    					$item_destination = $item_link->getAttribute('name');
    					$item_destination_format = '/'. $item_destination_url[1] .'/i';
    			
    					if (preg_match($item_destination_format, $item_destination)) {
    			
    						$rss_item_description_search = $item_link->nextSibling;
    				
    						$found = 'false';
    						while ($found == 'false') {
    							// Check attributes
    							
    							if ($rss_item_description_search->nodeName == '#text') {
    								$rss_item_description_search = $rss_item_description_search->nextSibling;
    							}
    							else {
    								if ($rss_item_description_search->hasAttribute('height')) {
    									$divs = $rss_item_description_search->getElementsByTagName('div');
    							
    									foreach ($divs as $div) {
    										if ($div->hasAttribute('align')) {
    											if ($div->getAttribute('align') == 'left') {
    											
    												
    												
    												// Get contents
    												
    												$div_contents = $div->childNodes;
    												
    												$fragment_count = '0';
    												
    												foreach ($div_contents as $div_content) {
    													
    													// Convert tags to entities
    													
    													$tag = $div_content->nodeName;
    													
    													// Is text?
    													
    													if ($tag == '#text') {
    														$is_text = true;
    													}
    													else {
    														$is_text = false;
    													}
    													
    													// What is it's contents
    													
    													$content = $div_content->nodeValue;
    													
    													// Does it have attributes
    													
    													if ($div_content->hasAttributes()) {
    														$has_attributes = true;
    														$attributes = $div_content->attributes;
    													}
    													else {
    														$has_attributes = false;
    														$attributes = '';
    													}
    													
    													$fragments[$fragment_count] = prepare_tags($tag,$is_text,$content,$has_attributes,$attributes);
    													
    													$fragment_count++;
    												}
    												
    												$clean_text = combine_frags($fragments);
    												
    												// Create Description
    												
    												$rss_item_description = $rss_dom->createElement('description', $clean_text);
    												$rss_item->appendChild($rss_item_description);
    											}
    											
    											
    										}
    									}
    						
    									$found = 'true';
    								}
    								else {
    									$rss_item_description_search = $rss_item_description_search->nextSibling;
    								}
    							}
    						}	
    					}
    				}
    			}
    		}
    	}
    }
    
    echo $rss_dom->saveXML();
    

    Dritz on
    There I was, 3DS: 2621-2671-9899 (Ekera), Wii U: LostCrescendo
  • JaninJanin Registered User
    edited December 2006
    Before I begin my rant, here's how to use a return value. This should allow you to fix the prepare_tags() and combine_frags(). The text after is of interest only if you want to become a better programmer.
    function example_function($first, $second) {
      // Example for building a string piece by piece
      $return_value = $first;
      $return_value = $return_value . $second;
    
      return $return_value;
    }
    
    $combined = example_function("First", "Second");
    

    You've got a good grasp of roughly where comments should go and how to make blocks out of the code. However, comments should explain "why" and not "what". Whenever you write a comment like "Initiate connection with site and save copy", it means you should separate that block out into a function.

    For example:
    // Initiate connection with site and save copy
    
    $ch = curl_init($site);
    $fp = @fopen($save_file, "w");
    curl_setopt($ch, CURLOPT_FILE, $fp);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
    

    Could be changed to:
    // Original spot
    save_site_to($site, $save_file);
    
    // ...
    
    // Further down in the file
    function save_site_to($url, $file) {
      $ch = curl_init($url);
      $fp = @fopen($file, "w");
      curl_setopt($ch, CURLOPT_FILE, $fp);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_exec($ch);
      curl_close($ch);
      fclose($fp);
    }
    

    You should especially apply this to that giant foreach at the end of the code. Whenever you get that level of nested loops and ifs, it's an alarm bell to separate parts of your code. When you separate your code into small blocks of logically organized code, it becomes possible to verify correctness merely by sight. There is no way to check that giant loop is correct short of manually tracing it.

    On lines 210 and 213, it seems you know how to use booleans. So, why do you set $found to a string on lines 178 and 248?

    Janin on
    [SIGPIC][/SIGPIC]
Sign In or Register to comment.